update samples, fix SAT backend overflow in hints

This commit is contained in:
Laurent Perron
2020-11-30 18:58:09 +01:00
parent 675ba86d1b
commit a139418f17
9 changed files with 74 additions and 25 deletions

View File

@@ -157,6 +157,8 @@
#include "ortools/linear_solver/linear_solver_callback.h"
#include "ortools/port/proto_utils.h"
ABSL_DECLARE_FLAG(bool, linear_solver_enable_verbose_output);
namespace operations_research {
constexpr double kDefaultPrimalTolerance = 1e-07;

View File

@@ -40,7 +40,7 @@ void BinPackingMip() {
// [END program_part1]
// [START solver]
// Create the mip solver with the CBC backend.
// Create the mip solver with the SCIP backend.
MPSolver solver("bin_packing_mip", MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING);
// [END solver]

View File

@@ -14,7 +14,6 @@
# [START program]
# [START import]
from ortools.linear_solver import pywraplp
# [END import]
@@ -30,7 +29,6 @@ def create_data_model():
data['bin_capacity'] = 100
return data
# [END data_model]

View File

@@ -14,7 +14,6 @@
# [START program]
# [START import]
from ortools.linear_solver import pywraplp
# [END import]
@@ -35,7 +34,6 @@ def create_data_model():
data['num_constraints'] = 4
return data
# [END data_model]

View File

@@ -43,7 +43,7 @@ void MultipleKnapsackMip() {
// [END program_part1]
// [START solver]
// Create the mip solver with the CBC backend.
// Create the mip solver with the SCIP backend.
MPSolver solver("multiple_knapsack_mip",
MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING);
// [END solver]

View File

@@ -14,7 +14,6 @@
# [START program]
# [START import]
from ortools.linear_solver import pywraplp
# [END import]
@@ -34,7 +33,6 @@ def create_data_model():
data['bin_capacities'] = [100, 100, 100, 100, 100]
return data
# [END data_model]

View File

@@ -136,15 +136,8 @@ MPSolver::ResultStatus SatInterface::Solve(const MPSolverParameters& param) {
MPModelRequest request;
solver_->ExportModelToProto(request.mutable_model());
// If sat::SatParameters is compiled with proto-lite (go/mobile-cpp-protos),
// then serialize as non-human readable string. This is because proto-lite
// does not support reflection mechanism, which is a prerequisite for method
// like `ShortDebugString`.
if (!std::is_base_of<Message, sat::SatParameters>::value) {
request.set_solver_specific_parameters(parameters_.SerializeAsString());
} else {
request.set_solver_specific_parameters(parameters_.ShortDebugString());
}
request.set_solver_specific_parameters(
EncodeSatParametersAsString(parameters_));
request.set_enable_internal_solver_output(!quiet_);
const absl::StatusOr<MPSolutionResponse> status_or =
SatSolveProto(std::move(request), &interrupt_solve_);

View File

@@ -36,6 +36,13 @@ using google::protobuf::Message;
using google::protobuf::Message;
#endif
// Proto-lite disables some features of protos (see
// go/abp-libraries/proto2-lite) and messages inherit from MessageLite directly
// instead of inheriting from Message (which is itself a specialization of
// MessageLite).
constexpr bool kProtoLiteSatParameters =
!std::is_base_of<Message, sat::SatParameters>::value;
MPSolverResponseStatus ToMPSolverResponseStatus(sat::CpSolverStatus status,
bool has_objective) {
switch (status) {
@@ -64,13 +71,20 @@ absl::StatusOr<MPSolutionResponse> SatSolveProto(
params.set_num_search_workers(8);
params.set_log_search_progress(request.enable_internal_solver_output());
if (request.has_solver_specific_parameters()) {
// If code is compiled with proto-lite runtime, `solver_specific_parameters`
// should be encoded as non-human readable string from `SerializeAsString`.
if (!std::is_base_of<Message, sat::SatParameters>::value) {
CHECK(params.MergeFromString(request.solver_specific_parameters()));
// See EncodeSatParametersAsString() documentation.
if (kProtoLiteSatParameters) {
if (!params.MergeFromString(request.solver_specific_parameters())) {
return absl::InvalidArgumentError(
"solver_specific_parameters is not a valid binary stream of the "
"SatParameters proto");
}
} else {
ProtobufTextFormatMergeFromString(request.solver_specific_parameters(),
&params);
if (!ProtobufTextFormatMergeFromString(
request.solver_specific_parameters(), &params)) {
return absl::InvalidArgumentError(
"solver_specific_parameters is not a valid textual representation "
"of the SatParameters proto");
}
}
}
if (request.has_solver_time_limit_seconds()) {
@@ -148,9 +162,18 @@ absl::StatusOr<MPSolutionResponse> SatSolveProto(
for (int i = 0; i < size; ++i) {
const int var = request.model().solution_hint().var_index(i);
if (var >= var_scaling.size()) continue;
// To handle weird hint input values, we cap any large value to +/-
// mip_max_bound() which is also the min/max value of any variable once
// scaled.
double value =
request.model().solution_hint().var_value(i) * var_scaling[var];
if (std::abs(value) > params.mip_max_bound()) {
value = value > 0 ? params.mip_max_bound() : -params.mip_max_bound();
}
cp_model_hint->add_vars(var);
cp_model_hint->add_values(static_cast<int64>(std::round(
(request.model().solution_hint().var_value(i)) * var_scaling[var])));
cp_model_hint->add_values(static_cast<int64>(std::round(value)));
}
}
@@ -196,4 +219,18 @@ absl::StatusOr<MPSolutionResponse> SatSolveProto(
return response;
}
std::string EncodeSatParametersAsString(const sat::SatParameters& parameters) {
if (kProtoLiteSatParameters) {
// Here we use SerializeToString() instead of SerializeAsString() since the
// later ignores errors and returns an empty string instead (which can be a
// valid value when no fields are set).
std::string bytes;
CHECK(parameters.SerializeToString(&bytes));
return bytes;
}
return parameters.ShortDebugString();
}
} // namespace operations_research

View File

@@ -16,13 +16,36 @@
#include "absl/status/statusor.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/sat/sat_parameters.pb.h"
namespace operations_research {
// Solve the input MIP model with the SAT solver.
//
// If possible, std::move the request into this function call to avoid a copy.
//
// If you need to change the solver parameters, please use the
// EncodeSatParametersAsString() function below to set the request's
// solver_specific_parameters field.
absl::StatusOr<MPSolutionResponse> SatSolveProto(
MPModelRequest request, std::atomic<bool>* interrupt_solve = nullptr);
// Returns a string that should be used in MPModelRequest's
// solver_specific_parameters field to encode the SAT parameters.
//
// The returned string's content depends on the version of the proto library
// that is linked in the binary.
//
// By default it will contain the textual representation of the input proto.
// But when the proto-lite is used, it will contain the binary stream of the
// proto instead since it is not possible to build the textual representation in
// that case.
//
// The SatSolveProto() function will test if the proto-lite is used and expect a
// binary stream when it is the case. So in order for your code to be portable,
// you should always use this function to set the specific parameters.
std::string EncodeSatParametersAsString(const sat::SatParameters& parameters);
} // namespace operations_research
#endif // OR_TOOLS_LINEAR_SOLVER_SAT_PROTO_SOLVER_H_