From 44fc0c45e4d4f58d7e4cb7ee9d6356b6eddb8087 Mon Sep 17 00:00:00 2001 From: Corentin Le Molgat Date: Mon, 17 Jan 2022 09:27:18 +0100 Subject: [PATCH] sync gscip --- ortools/gscip/gscip.cc | 31 +++++++++++++++++++++++++++++++ ortools/gscip/gscip.proto | 7 +++++++ 2 files changed, 38 insertions(+) diff --git a/ortools/gscip/gscip.cc b/ortools/gscip/gscip.cc index a9b3583c1f..afb6f04d59 100644 --- a/ortools/gscip/gscip.cc +++ b/ortools/gscip/gscip.cc @@ -171,6 +171,29 @@ SCIP_PARAMSETTING ConvertMetaParamValue( } } +absl::Status CheckSolutionsInOrder(const GScipResult& result, + const bool is_maximize) { + auto objective_as_good_as = [is_maximize](double left, double right) { + if (is_maximize) { + return left >= right; + } + return left <= right; + }; + for (int i = 1; i < result.objective_values.size(); ++i) { + const double previous = result.objective_values[i - 1]; + const double current = result.objective_values[i]; + if (!objective_as_good_as(previous, current)) { + return util::InternalErrorBuilder() + << "Expected SCIP solutions to be in best objective order " + "first, but for " + << (is_maximize ? "maximization" : "minimization") + << " problem, the " << i - 1 << " objective is " << previous + << " and the " << i << " objective is " << current; + } + } + return absl::OkStatus(); +} + } // namespace const GScipVariableOptions& DefaultGScipVariableOptions() { @@ -779,6 +802,10 @@ absl::StatusOr GScip::Solve( RETURN_IF_SCIP_ERROR(SCIPwriteOrigProblem( scip_, params.scip_model_filename().c_str(), "cip", FALSE)); } + if (params.has_objective_limit()) { + RETURN_IF_SCIP_ERROR( + SCIPsetObjlimit(scip_, ScipInfClamp(params.objective_limit()))); + } // Install the message handler if necessary. We do this after setting the // parameters so that parameters that applies to the default message handler @@ -855,6 +882,7 @@ absl::StatusOr GScip::Solve( result.solutions.push_back(solution); result.objective_values.push_back(obj_value); } + RETURN_IF_ERROR(CheckSolutionsInOrder(result, ObjectiveIsMaximize())); // Can only check for primal ray if we made it past presolve. if (stage != SCIP_STAGE_PRESOLVING && SCIPhasPrimalRay(scip_)) { for (SCIP_VAR* v : variables_) { @@ -889,6 +917,9 @@ absl::StatusOr GScip::Solve( // the remainder of the buffer content would be lost. new_handler.reset(); } + if (params.has_objective_limit()) { + RETURN_IF_SCIP_ERROR(SCIPsetObjlimit(scip_, SCIP_INVALID)); + } RETURN_IF_SCIP_ERROR(SCIPresetParams(scip_)); // The `silence_output` and `search_logs_filename` parameters are special diff --git a/ortools/gscip/gscip.proto b/ortools/gscip/gscip.proto index a2f0864adc..5cb9781516 100644 --- a/ortools/gscip/gscip.proto +++ b/ortools/gscip/gscip.proto @@ -111,6 +111,13 @@ message GScipParameters { // How many solutions to retrieve from the solution pool (if this many exist). // At least one solution will always be returned, even if num_solutions < 1. optional int32 num_solutions = 17; + + // If set, ignore all solutions worse than objective_limit, for details see + // SCIPsetObjlimit(). Note that the solution pool will still contain solutions + // worse than the limit as SCIP uses these to run improvement heuristics, and + // if you query all solutions at the end of the solve they will be present, + // even if you found no solution that met the limit and returned infeasible. + optional double objective_limit = 18; } // TODO(user): this should be machine generated by script and contain all of