18 #if !defined(_MSC_VER)
32 #include "absl/container/flat_hash_set.h"
33 #include "absl/status/status.h"
34 #include "absl/status/statusor.h"
35 #include "absl/strings/ascii.h"
36 #include "absl/strings/match.h"
37 #include "absl/strings/str_cat.h"
38 #include "absl/strings/str_format.h"
39 #include "absl/strings/str_replace.h"
40 #include "absl/synchronization/mutex.h"
41 #include "absl/synchronization/notification.h"
42 #include "absl/time/time.h"
50 #include "ortools/linear_solver/linear_solver.pb.h"
58 "Systematically verify the solution when calling Solve()"
59 ", and change the return value of Solve() to ABNORMAL if"
60 " an error was detected.");
62 "If --verify_solution is set: LOG(ERROR) all errors detected"
63 " during the verification of the solution.");
64 ABSL_FLAG(
bool, linear_solver_enable_verbose_output,
false,
65 "If set, enables verbose output for the solver. Setting this flag"
66 " is the same as calling MPSolver::EnableOutput().");
68 ABSL_FLAG(
bool, mpsolver_bypass_model_validation,
false,
69 "If set, the user-provided Model won't be verified before Solve()."
70 " Invalid models will typically trigger various error responses"
71 " from the underlying solvers; sometimes crashes.");
76 switch (solver_type) {
77 case MPModelRequest::PDLP_LINEAR_PROGRAMMING:
78 case MPModelRequest::GLOP_LINEAR_PROGRAMMING:
79 case MPModelRequest::CLP_LINEAR_PROGRAMMING:
80 case MPModelRequest::GLPK_LINEAR_PROGRAMMING:
81 case MPModelRequest::GUROBI_LINEAR_PROGRAMMING:
82 case MPModelRequest::HIGHS_LINEAR_PROGRAMMING:
83 case MPModelRequest::XPRESS_LINEAR_PROGRAMMING:
84 case MPModelRequest::CPLEX_LINEAR_PROGRAMMING:
87 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING:
88 case MPModelRequest::GLPK_MIXED_INTEGER_PROGRAMMING:
89 case MPModelRequest::CBC_MIXED_INTEGER_PROGRAMMING:
90 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING:
91 case MPModelRequest::KNAPSACK_MIXED_INTEGER_PROGRAMMING:
92 case MPModelRequest::BOP_INTEGER_PROGRAMMING:
93 case MPModelRequest::SAT_INTEGER_PROGRAMMING:
94 case MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING:
95 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING:
96 case MPModelRequest::CPLEX_MIXED_INTEGER_PROGRAMMING:
99 LOG(DFATAL) <<
"Invalid SolverType: " << solver_type;
105 if (
var ==
nullptr)
return 0.0;
111 if (
var ==
nullptr)
return;
113 auto it = coefficients_.find(
var);
121 if (it != coefficients_.end() && it->second != 0.0) {
122 const double old_value = it->second;
128 auto insertion_result = coefficients_.insert(std::make_pair(
var, coeff));
129 const double old_value =
130 insertion_result.second ? 0.0 : insertion_result.first->second;
131 insertion_result.first->second = coeff;
137 coefficients_.clear();
141 const bool change =
lb != lb_ ||
ub != ub_;
151 LOG(DFATAL) <<
"Dual value only available for continuous problems";
160 LOG(DFATAL) <<
"Basis status only available for continuous problems";
170 bool MPConstraint::ContainsNewVariables() {
172 for (
const auto& entry : coefficients_) {
173 const int variable_index = entry.first->index();
174 if (variable_index >= last_variable_index ||
186 if (
var ==
nullptr)
return 0.0;
192 if (
var ==
nullptr)
return;
194 auto it = coefficients_.find(
var);
197 if (it == coefficients_.end() || it->second == 0.0)
return;
200 coefficients_[
var] = coeff;
212 for (
auto var_value_pair : linear_expr.
terms()) {
214 <<
"Bad MPVariable* in LinearExpr, did you try adding an integer to an "
215 "MPVariable* directly?";
221 bool is_maximization) {
222 CheckLinearExpr(*interface_->
solver_, linear_expr);
224 coefficients_.clear();
226 for (
const auto& kv : linear_expr.
terms()) {
233 CheckLinearExpr(*interface_->
solver_, linear_expr);
235 for (
const auto& kv : linear_expr.
terms()) {
242 coefficients_.clear();
282 return (integer_ && interface_->
IsMIP()) ? round(solution_value_)
288 return solution_value_;
293 LOG(DFATAL) <<
"Reduced cost only available for continuous problems";
297 return reduced_cost_;
302 LOG(DFATAL) <<
"Basis status only available for continuous problems";
313 const bool change =
lb != lb_ ||
ub != ub_;
331 if (priority == branching_priority_)
return;
332 branching_priority_ = priority;
341 return interface_->SolverVersion();
349 if (num_threads < 1) {
350 return absl::InvalidArgumentError(
"num_threads must be a positive number.");
352 const absl::Status
status = interface_->SetNumThreads(num_threads);
354 num_threads_ = num_threads;
361 solver_specific_parameter_string_ =
parameters;
362 return interface_->SetSolverSpecificParametersAsString(
parameters);
367 #if defined(USE_CLP) || defined(USE_CBC)
373 #if defined(USE_GLPK)
376 #if defined(USE_HIGHS)
383 #if defined(USE_SCIP)
388 #if defined(USE_CPLEX)
391 #if defined(USE_XPRESS)
398 DCHECK(solver !=
nullptr);
408 #if defined(USE_CLP) || defined(USE_CBC)
416 #if defined(USE_GLPK)
418 return BuildGLPKInterface(
false, solver);
420 return BuildGLPKInterface(
true, solver);
422 #if defined(USE_HIGHS)
424 return BuildHighsInterface(
false, solver);
426 return BuildHighsInterface(
true, solver);
428 #if defined(USE_SCIP)
436 #if defined(USE_CPLEX)
438 return BuildCplexInterface(
false, solver);
440 return BuildCplexInterface(
true, solver);
442 #if defined(USE_XPRESS)
444 return BuildXpressInterface(
true, solver);
446 return BuildXpressInterface(
false, solver);
450 LOG(FATAL) <<
"Linear solver not recognized.";
457 int NumDigits(
int n) {
460 #if defined(_MSC_VER)
461 return static_cast<int>(
std::max(1.0L, log(1.0L * n) / log(10.0L) + 1.0));
463 return static_cast<int>(
std::max(1.0, log10(
static_cast<double>(n)) + 1.0));
472 construction_time_(
absl::Now()) {
473 interface_.reset(BuildSolverInterface(
this));
474 if (absl::GetFlag(FLAGS_linear_solver_enable_verbose_output)) {
477 objective_.reset(
new MPObjective(interface_.get()));
535 struct NamedOptimizationProblemType {
541 #if defined(_MSC_VER)
570 const std::string
id =
571 absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{
"-",
"_"}});
575 if (MPModelRequest::SolverType_Parse(
id, &solver_type)) {
581 std::string lower_id = absl::AsciiStrToLower(
id);
584 if (absl::EndsWith(lower_id,
"_mip")) {
585 lower_id = lower_id.substr(0, lower_id.size() - 4);
589 if (lower_id ==
"cp_sat") {
595 if (named_solver.name == lower_id) {
596 *type = named_solver.problem_type;
607 if (named_solver.problem_type == optimization_problem_type) {
608 return named_solver.name;
611 LOG(FATAL) <<
"Unrecognized solver type: "
612 <<
static_cast<int>(optimization_problem_type);
618 std::string* error) {
619 DCHECK(solver_type !=
nullptr);
620 DCHECK(error !=
nullptr);
623 *error = absl::StrCat(
"Solver type: ", text,
" does not exist.");
630 const std::string& solver_id) {
640 LOG(WARNING) <<
"Unrecognized solver type: " << solver_id;
644 LOG(WARNING) <<
"Support for " << solver_id
645 <<
" not linked in, or the license was not found.";
653 if (!variable_name_to_index_) GenerateVariableNameIndex();
655 absl::flat_hash_map<std::string, int>::const_iterator it =
656 variable_name_to_index_->find(var_name);
657 if (it == variable_name_to_index_->end())
return nullptr;
658 return variables_[it->second];
662 const std::string& constraint_name)
const {
663 if (!constraint_name_to_index_) GenerateConstraintNameIndex();
665 const auto it = constraint_name_to_index_->find(constraint_name);
666 if (it == constraint_name_to_index_->end())
return nullptr;
667 return constraints_[it->second];
673 const MPModelProto& input_model, std::string* error_message) {
680 return LoadModelFromProtoInternal(input_model,
true,
686 const MPModelProto& input_model, std::string* error_message) {
690 GenerateVariableNameIndex();
691 GenerateConstraintNameIndex();
693 return LoadModelFromProtoInternal(input_model,
false,
698 MPSolverResponseStatus MPSolver::LoadModelFromProtoInternal(
699 const MPModelProto& input_model,
bool clear_names,
700 bool check_model_validity, std::string* error_message) {
701 CHECK(error_message !=
nullptr);
702 if (check_model_validity) {
704 if (!error.empty()) {
705 *error_message = error;
707 <<
"Invalid model given to LoadModelFromProto(): " << error;
708 if (absl::GetFlag(FLAGS_mpsolver_bypass_model_validation)) {
710 <<
"Ignoring the model error(s) because of"
711 <<
" --mpsolver_bypass_model_validation.";
713 return absl::StrContains(error,
"Infeasible") ? MPSOLVER_INFEASIBLE
714 : MPSOLVER_MODEL_INVALID;
719 if (input_model.has_quadratic_objective()) {
721 "Optimizing a quadratic objective is only supported through direct "
722 "proto solves. Please use MPSolver::SolveWithProto, or the solver's "
723 "direct proto solve function.";
724 return MPSOLVER_MODEL_INVALID;
729 const std::string empty;
730 for (
int i = 0; i < input_model.variable_size(); ++i) {
731 const MPVariableProto& var_proto = input_model.variable(i);
733 MakeNumVar(var_proto.lower_bound(), var_proto.upper_bound(),
734 clear_names ? empty : var_proto.name());
736 if (var_proto.branching_priority() != 0) {
739 objective->SetCoefficient(
variable, var_proto.objective_coefficient());
742 for (
const MPConstraintProto& ct_proto : input_model.constraint()) {
743 if (ct_proto.lower_bound() == -
infinity() &&
744 ct_proto.upper_bound() ==
infinity()) {
748 MPConstraint*
const ct =
750 clear_names ? empty : ct_proto.name());
751 ct->set_is_lazy(ct_proto.is_lazy());
752 for (
int j = 0; j < ct_proto.var_index_size(); ++j) {
753 ct->SetCoefficient(variables_[ct_proto.var_index(j)],
754 ct_proto.coefficient(j));
758 for (
const MPGeneralConstraintProto& general_constraint :
759 input_model.general_constraint()) {
760 switch (general_constraint.general_constraint_case()) {
761 case MPGeneralConstraintProto::kIndicatorConstraint: {
763 general_constraint.indicator_constraint().constraint();
770 MPConstraint*
const constraint =
new MPConstraint(
771 constraint_index,
proto.lower_bound(),
proto.upper_bound(),
772 clear_names ?
"" :
proto.name(), interface_.get());
773 if (constraint_name_to_index_) {
778 constraint_is_extracted_.push_back(
false);
781 for (
int j = 0; j <
proto.var_index_size(); ++j) {
783 proto.coefficient(j));
787 variables_[general_constraint.indicator_constraint().var_index()];
790 general_constraint.indicator_constraint().var_value();
792 if (!interface_->AddIndicatorConstraint(
constraint)) {
793 *error_message =
"Solver doesn't support indicator constraints";
794 return MPSOLVER_MODEL_INVALID;
799 *error_message = absl::StrFormat(
800 "Optimizing general constraints of type %i is only supported "
801 "through direct proto solves. Please use MPSolver::SolveWithProto, "
802 "or the solver's direct proto solve function.",
803 general_constraint.general_constraint_case());
804 return MPSOLVER_MODEL_INVALID;
808 objective->SetOptimizationDirection(input_model.maximize());
809 if (input_model.has_objective_offset()) {
810 objective->SetOffset(input_model.objective_offset());
814 solution_hint_.clear();
815 for (
int i = 0; i < input_model.solution_hint().var_index_size(); ++i) {
816 solution_hint_.push_back(
817 std::make_pair(variables_[input_model.solution_hint().var_index(i)],
818 input_model.solution_hint().var_value(i)));
820 return MPSOLVER_MODEL_IS_VALID;
824 MPSolverResponseStatus ResultStatusToMPSolverResponseStatus(
828 return MPSOLVER_OPTIMAL;
830 return MPSOLVER_FEASIBLE;
832 return MPSOLVER_INFEASIBLE;
834 return MPSOLVER_UNBOUNDED;
836 return MPSOLVER_ABNORMAL;
838 return MPSOLVER_MODEL_INVALID;
840 return MPSOLVER_NOT_SOLVED;
842 return MPSOLVER_UNKNOWN_STATUS;
850 ResultStatusToMPSolverResponseStatus(interface_->result_status_));
859 if (interface_->IsMIP()) {
860 response->set_best_objective_bound(interface_->best_objective_bound());
875 bool InCategory(
int status,
int category) {
876 if (category == MPSOLVER_OPTIMAL)
return status == MPSOLVER_OPTIMAL;
878 return status == category;
881 void AppendStatusStr(
const std::string& msg, MPSolutionResponse*
response) {
883 absl::StrCat(
response->status_str(),
884 (
response->status_str().empty() ?
"" :
"\n"), msg));
891 std::atomic<bool>* interrupt) {
894 if (interrupt !=
nullptr &&
896 response->set_status(MPSOLVER_INCOMPATIBLE_OPTIONS);
898 "Called MPSolver::SolveWithProto with an underlying solver that "
899 "doesn't support interruption.");
903 MPSolver solver(model_request.model().name(),
905 model_request.solver_type()));
906 if (model_request.enable_internal_solver_output()) {
912 auto optional_response =
913 solver.interface_->DirectlySolveProto(model_request, interrupt);
914 if (optional_response) {
915 *
response = std::move(optional_response).value();
919 const absl::optional<LazyMutableCopy<MPModelProto>> optional_model =
921 if (!optional_model) {
922 LOG_IF(WARNING, model_request.enable_internal_solver_output())
923 <<
"Failed to extract a valid model from protocol buffer. Status: "
924 << ProtoEnumToString<MPSolverResponseStatus>(
response->status()) <<
" ("
928 std::string error_message;
929 response->set_status(solver.LoadModelFromProtoInternal(
930 optional_model->get(),
true,
931 false, &error_message));
934 if (
response->status() != MPSOLVER_MODEL_IS_VALID) {
935 response->set_status_str(error_message);
936 LOG_IF(WARNING, model_request.enable_internal_solver_output())
937 <<
"LoadModelFromProtoInternal() failed even though the model was "
939 << ProtoEnumToString<MPSolverResponseStatus>(
response->status()) <<
" ("
940 <<
response->status() <<
"); Error: " << error_message;
943 if (model_request.has_solver_time_limit_seconds()) {
945 absl::Seconds(model_request.solver_time_limit_seconds()));
947 std::string warning_message;
948 if (model_request.has_solver_specific_parameters()) {
950 model_request.solver_specific_parameters())) {
951 if (model_request.ignore_solver_specific_parameters_failure()) {
954 "Warning: the solver specific parameters were not successfully "
957 response->set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
963 if (interrupt ==
nullptr) {
969 const absl::Time start_time = absl::Now();
970 absl::Time interrupt_time;
971 bool interrupted_by_user =
false;
973 absl::Notification solve_finished;
974 auto polling_func = [&interrupt, &solve_finished, &solver,
975 &interrupted_by_user, &interrupt_time,
977 constexpr absl::Duration kPollDelay = absl::Microseconds(100);
978 constexpr absl::Duration kMaxInterruptionDelay = absl::Seconds(10);
980 while (!interrupt->load()) {
981 if (solve_finished.HasBeenNotified())
return;
982 absl::SleepFor(kPollDelay);
987 solver.InterruptSolve();
988 interrupt_time = absl::Now();
989 interrupted_by_user =
true;
1004 for (absl::Duration poll_delay = kPollDelay;
1005 absl::Now() <= interrupt_time + kMaxInterruptionDelay;
1007 if (solve_finished.WaitForNotificationWithTimeout(poll_delay)) {
1010 solver.InterruptSolve();
1015 <<
"MPSolver::InterruptSolve() seems to be ignored by the "
1016 "underlying solver, despite repeated calls over at least "
1017 << absl::FormatDuration(kMaxInterruptionDelay)
1018 <<
". Solver type used: "
1019 << MPModelRequest_SolverType_Name(model_request.solver_type());
1032 thread_pool.
Schedule(polling_func);
1036 if (!interrupt->load()) {
1038 solver.FillSolutionResponseProto(
response);
1040 response->set_status(MPSOLVER_CANCELLED_BY_USER);
1042 "Solve not started, because the user set the atomic<bool> in "
1043 "MPSolver::SolveWithProto() to true before solving could "
1046 solve_finished.Notify();
1051 if (interrupted_by_user) {
1054 if (InCategory(
response->status(), MPSOLVER_NOT_SOLVED)) {
1055 response->set_status(MPSOLVER_CANCELLED_BY_USER);
1059 "User interrupted MPSolver::SolveWithProto() by setting the "
1060 "atomic<bool> to true at %s (%s after solving started.)",
1061 absl::FormatTime(interrupt_time),
1062 absl::FormatDuration(interrupt_time - start_time)),
1067 if (!warning_message.empty()) {
1068 AppendStatusStr(warning_message,
response);
1073 DCHECK(output_model !=
nullptr);
1074 output_model->Clear();
1076 output_model->set_name(
Name());
1079 MPVariableProto*
const variable_proto = output_model->add_variable();
1082 variable_proto->set_name(
var->name());
1083 variable_proto->set_lower_bound(
var->lb());
1084 variable_proto->set_upper_bound(
var->ub());
1085 variable_proto->set_is_integer(
var->integer());
1086 if (objective_->GetCoefficient(
var) != 0.0) {
1087 variable_proto->set_objective_coefficient(
1088 objective_->GetCoefficient(
var));
1090 if (
var->branching_priority() != 0) {
1091 variable_proto->set_branching_priority(
var->branching_priority());
1101 absl::flat_hash_map<const MPVariable*, int> var_to_index;
1102 for (
int j = 0; j < static_cast<int>(variables_.size()); ++j) {
1103 var_to_index[variables_[j]] = j;
1108 MPConstraintProto* constraint_proto;
1110 MPGeneralConstraintProto*
const general_constraint_proto =
1111 output_model->add_general_constraint();
1113 MPIndicatorConstraint*
const indicator_constraint_proto =
1114 general_constraint_proto->mutable_indicator_constraint();
1115 indicator_constraint_proto->set_var_index(
1118 constraint_proto = indicator_constraint_proto->mutable_constraint();
1120 constraint_proto = output_model->add_constraint();
1128 std::vector<std::pair<int, double>> linear_term;
1129 for (
const auto& entry :
constraint->coefficients_) {
1132 DCHECK_NE(-1, var_index);
1133 const double coeff = entry.second;
1134 linear_term.push_back(std::pair<int, double>(var_index, coeff));
1138 std::sort(linear_term.begin(), linear_term.end());
1140 for (
const std::pair<int, double>& var_and_coeff : linear_term) {
1141 constraint_proto->add_var_index(var_and_coeff.first);
1142 constraint_proto->add_coefficient(var_and_coeff.second);
1146 output_model->set_maximize(
Objective().maximization());
1147 output_model->set_objective_offset(
Objective().offset());
1149 if (!solution_hint_.empty()) {
1150 PartialVariableAssignment*
const hint =
1151 output_model->mutable_solution_hint();
1152 for (
const auto& var_value_pair : solution_hint_) {
1153 hint->add_var_index(var_value_pair.first->index());
1154 hint->add_var_value(var_value_pair.second);
1162 if (
response.status() != MPSOLVER_OPTIMAL &&
1163 response.status() != MPSOLVER_FEASIBLE) {
1164 return absl::InvalidArgumentError(absl::StrCat(
1165 "Cannot load a solution unless its status is OPTIMAL or FEASIBLE"
1167 ProtoEnumToString<MPSolverResponseStatus>(
response.status()),
")"));
1172 if (
static_cast<size_t>(
response.variable_value_size()) !=
1173 variables_.size()) {
1174 return absl::InvalidArgumentError(absl::StrCat(
1175 "Trying to load a solution whose number of variables (",
1177 ") does not correspond to the Solver's (", variables_.size(),
")"));
1179 interface_->ExtractModel();
1183 double largest_error = 0;
1184 int num_vars_out_of_bounds = 0;
1185 int last_offending_var = -1;
1186 for (
int i = 0; i <
response.variable_value_size(); ++i) {
1187 const double var_value =
response.variable_value(i);
1190 const double lb_error =
var->lb() - var_value;
1191 const double ub_error = var_value -
var->ub();
1192 if (lb_error > tolerance || ub_error > tolerance) {
1193 ++num_vars_out_of_bounds;
1195 last_offending_var = i;
1198 if (num_vars_out_of_bounds > 0) {
1199 return absl::InvalidArgumentError(absl::StrCat(
1200 "Loaded a solution whose variables matched the solver's, but ",
1201 num_vars_out_of_bounds,
" of ", variables_.size(),
1202 " variables were out of their bounds, by more than the primal"
1203 " tolerance which is: ",
1204 tolerance,
". Max error: ", largest_error,
", last offender var is #",
1205 last_offending_var,
": '", variables_[last_offending_var]->name(),
1209 for (
int i = 0; i <
response.variable_value_size(); ++i) {
1210 variables_[i]->set_solution_value(
response.variable_value(i));
1212 if (
response.dual_value_size() > 0) {
1213 if (
static_cast<size_t>(
response.dual_value_size()) !=
1214 constraints_.size()) {
1215 return absl::InvalidArgumentError(absl::StrCat(
1216 "Trying to load a dual solution whose number of entries (",
1217 response.dual_value_size(),
") does not correspond to the Solver's (",
1218 constraints_.size(),
")"));
1220 for (
int i = 0; i <
response.dual_value_size(); ++i) {
1221 constraints_[i]->set_dual_value(
response.dual_value(i));
1224 if (
response.reduced_cost_size() > 0) {
1225 if (
static_cast<size_t>(
response.reduced_cost_size()) !=
1226 variables_.size()) {
1227 return absl::InvalidArgumentError(absl::StrCat(
1228 "Trying to load a reduced cost solution whose number of entries (",
1230 ") does not correspond to the Solver's (", variables_.size(),
")"));
1232 for (
int i = 0; i <
response.reduced_cost_size(); ++i) {
1233 variables_[i]->set_reduced_cost(
response.reduced_cost(i));
1238 if (
response.has_objective_value()) {
1239 interface_->objective_value_ =
response.objective_value();
1241 if (
response.has_best_objective_bound()) {
1242 interface_->best_objective_bound_ =
response.best_objective_bound();
1247 return absl::OkStatus();
1252 absl::MutexLock lock(&global_count_mutex_);
1253 global_num_variables_ += variables_.size();
1254 global_num_constraints_ += constraints_.size();
1259 if (variable_name_to_index_) {
1260 variable_name_to_index_->clear();
1262 variable_is_extracted_.clear();
1263 if (constraint_name_to_index_) {
1264 constraint_name_to_index_->clear();
1266 constraint_is_extracted_.clear();
1267 interface_->Reset();
1268 solution_hint_.clear();
1276 const std::vector<BasisStatus>& variable_statuses,
1277 const std::vector<BasisStatus>& constraint_statuses) {
1278 interface_->SetStartingLpBasis(variable_statuses, constraint_statuses);
1282 const std::string&
name) {
1285 new MPVariable(var_index, lb, ub, integer,
name, interface_.get());
1286 if (variable_name_to_index_) {
1289 variables_.push_back(v);
1290 variable_is_extracted_.push_back(
false);
1291 interface_->AddVariable(v);
1296 const std::string&
name) {
1301 const std::string&
name) {
1310 const std::string&
name,
1311 std::vector<MPVariable*>* vars) {
1313 if (nb <= 0)
return;
1314 const int num_digits = NumDigits(nb);
1315 for (
int i = 0; i < nb; ++i) {
1320 absl::StrFormat(
"%s%0*d",
name.c_str(), num_digits, i);
1321 vars->push_back(
MakeVar(lb, ub, integer, vname));
1327 const std::string&
name,
1328 std::vector<MPVariable*>* vars) {
1333 const std::string&
name,
1334 std::vector<MPVariable*>* vars) {
1339 std::vector<MPVariable*>* vars) {
1352 const std::string&
name) {
1356 if (constraint_name_to_index_) {
1361 constraint_is_extracted_.push_back(
false);
1375 const std::string&
name) {
1376 CheckLinearExpr(*
this,
range.linear_expr());
1379 for (
const auto& kv :
range.linear_expr().terms()) {
1385 int MPSolver::ComputeMaxConstraintSize(
int min_constraint_index,
1386 int max_constraint_index)
const {
1387 int max_constraint_size = 0;
1388 DCHECK_GE(min_constraint_index, 0);
1389 DCHECK_LE(max_constraint_index, constraints_.size());
1390 for (
int i = min_constraint_index; i < max_constraint_index; ++i) {
1392 if (
static_cast<int>(
ct->coefficients_.size()) > max_constraint_size) {
1393 max_constraint_size =
ct->coefficients_.size();
1396 return max_constraint_size;
1399 bool MPSolver::HasInfeasibleConstraints()
const {
1400 bool hasInfeasibleConstraints =
false;
1401 for (
int i = 0; i < static_cast<int>(constraints_.size()); ++i) {
1402 if (constraints_[i]->lb() > constraints_[i]->ub()) {
1403 LOG(WARNING) <<
"Constraint " << constraints_[i]->name() <<
" (" << i
1404 <<
") has contradictory bounds:"
1405 <<
" lower bound = " << constraints_[i]->lb()
1406 <<
" upper bound = " << constraints_[i]->ub();
1407 hasInfeasibleConstraints =
true;
1410 return hasInfeasibleConstraints;
1413 bool MPSolver::HasIntegerVariables()
const {
1414 for (
const MPVariable*
const variable : variables_) {
1422 return Solve(default_param);
1431 if (HasInfeasibleConstraints()) {
1433 return interface_->result_status_;
1437 if (absl::GetFlag(FLAGS_verify_solution)) {
1439 VLOG(1) <<
"--verify_solution enabled, but the solver did not find a"
1440 <<
" solution: skipping the verification.";
1443 absl::GetFlag(FLAGS_log_verification_errors))) {
1445 interface_->result_status_ =
status;
1448 DCHECK_EQ(interface_->result_status_,
status);
1453 interface_->Write(file_name);
1458 const std::string prefix =
"Variable '" +
var.
name() +
"': domain = ";
1461 return prefix +
"∅";
1465 if (
var.integer() &&
var.ub() -
var.lb() <= 1) {
1466 const int64_t lb =
static_cast<int64_t
>(ceil(
var.lb()));
1467 const int64_t ub =
static_cast<int64_t
>(floor(
var.ub()));
1469 return prefix +
"∅";
1470 }
else if (lb == ub) {
1471 return absl::StrFormat(
"%s{ %d }", prefix.c_str(), lb);
1473 return absl::StrFormat(
"%s{ %d, %d }", prefix.c_str(), lb, ub);
1477 if (
var.lb() ==
var.ub()) {
1478 return absl::StrFormat(
"%s{ %f }", prefix.c_str(),
var.lb());
1480 return prefix + (
var.integer() ?
"Integer" :
"Real") +
" in " +
1482 ? std::string(
"]-∞")
1483 :
absl::StrFormat(
"[%f",
var.lb())) +
1485 (
var.ub() >= MPSolver::infinity() ? std::string(
"+∞[")
1486 :
absl::StrFormat(
"%f]",
var.ub()));
1489 std::string PrettyPrintConstraint(
const MPConstraint& constraint) {
1490 std::string prefix =
"Constraint '" + constraint.name() +
"': ";
1493 constraint.lb() > constraint.ub()) {
1494 return prefix +
"ALWAYS FALSE";
1498 return prefix +
"ALWAYS TRUE";
1500 prefix +=
"<linear expr>";
1502 if (constraint.lb() == constraint.ub()) {
1503 return absl::StrFormat(
"%s = %f", prefix.c_str(), constraint.lb());
1507 return absl::StrFormat(
"%s ≤ %f", prefix.c_str(), constraint.ub());
1510 return absl::StrFormat(
"%s ≥ %f", prefix.c_str(), constraint.lb());
1512 return absl::StrFormat(
"%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(),
1518 interface_->ExtractModel();
1521 if (std::isnan(
value)) {
1522 return absl::InvalidArgumentError(
1523 absl::StrCat(
"NaN value for ", PrettyPrintVar(*
variable)));
1525 if (value < variable->lb()) {
1532 return absl::OkStatus();
1537 if (!interface_->CheckSolutionIsSynchronizedAndExists())
return {};
1538 std::vector<double> activities(constraints_.size(), 0.0);
1539 for (
int i = 0; i < static_cast<int>(constraints_.size()); ++i) {
1542 for (
const auto& entry :
constraint.coefficients_) {
1543 sum.
Add(entry.first->solution_value() * entry.second);
1545 activities[i] = sum.
Value();
1552 double max_observed_error = 0;
1553 if (tolerance < 0) tolerance =
infinity();
1559 const double value =
var.solution_value();
1561 if (std::isnan(
value)) {
1564 LOG_IF(ERROR, log_errors) <<
"NaN value for " << PrettyPrintVar(
var);
1569 if (
value <
var.lb() - tolerance) {
1572 LOG_IF(ERROR, log_errors)
1573 <<
"Value " <<
value <<
" too low for " << PrettyPrintVar(
var);
1578 if (
value >
var.ub() + tolerance) {
1581 LOG_IF(ERROR, log_errors)
1582 <<
"Value " <<
value <<
" too high for " << PrettyPrintVar(
var);
1587 if (fabs(
value - round(
value)) > tolerance) {
1589 max_observed_error =
1591 LOG_IF(ERROR, log_errors)
1592 <<
"Non-integer value " <<
value <<
" for " << PrettyPrintVar(
var);
1596 if (!
IsMIP() && HasIntegerVariables()) {
1597 LOG_IF(INFO, log_errors) <<
"Skipped variable integrality check, because "
1598 <<
"a continuous relaxation of the model was "
1599 <<
"solved (i.e., the selected solver does not "
1600 <<
"support integer variables).";
1605 for (
int i = 0; i < static_cast<int>(constraints_.size()); ++i) {
1607 const double activity = activities[i];
1609 double inaccurate_activity = 0.0;
1610 for (
const auto& entry :
constraint.coefficients_) {
1611 inaccurate_activity += entry.first->solution_value() * entry.second;
1614 if (std::isnan(activity) || std::isnan(inaccurate_activity)) {
1617 LOG_IF(ERROR, log_errors)
1618 <<
"NaN value for " << PrettyPrintConstraint(
constraint);
1628 max_observed_error =
1630 LOG_IF(ERROR, log_errors)
1631 <<
"Activity " << activity <<
" too low for "
1633 }
else if (inaccurate_activity <
constraint.
lb() - tolerance) {
1634 LOG_IF(WARNING, log_errors)
1635 <<
"Activity " << activity <<
", computed with the (inaccurate)"
1636 <<
" standard sum of its terms, is too low for "
1643 max_observed_error =
1645 LOG_IF(ERROR, log_errors)
1646 <<
"Activity " << activity <<
" too high for "
1648 }
else if (inaccurate_activity >
constraint.
ub() + tolerance) {
1649 LOG_IF(WARNING, log_errors)
1650 <<
"Activity " << activity <<
", computed with the (inaccurate)"
1651 <<
" standard sum of its terms, is too high for "
1662 double inaccurate_objective_value = objective.
offset();
1663 for (
const auto& entry : objective.coefficients_) {
1664 const double term = entry.first->solution_value() * entry.second;
1665 objective_sum.
Add(term);
1666 inaccurate_objective_value += term;
1668 const double actual_objective_value = objective_sum.
Value();
1670 objective.
Value(), actual_objective_value, tolerance, tolerance)) {
1673 max_observed_error, fabs(actual_objective_value - objective.
Value()));
1674 LOG_IF(ERROR, log_errors)
1675 <<
"Objective value " << objective.
Value() <<
" isn't accurate"
1676 <<
", it should be " << actual_objective_value
1677 <<
" (delta=" << actual_objective_value - objective.
Value() <<
").";
1679 inaccurate_objective_value,
1680 tolerance, tolerance)) {
1681 LOG_IF(WARNING, log_errors)
1682 <<
"Objective value " << objective.
Value() <<
" doesn't correspond"
1683 <<
" to the value computed with the standard (and therefore inaccurate)"
1684 <<
" sum of its terms.";
1686 if (num_errors > 0) {
1687 LOG_IF(ERROR, log_errors)
1688 <<
"There were " << num_errors <<
" errors above the tolerance ("
1689 << tolerance <<
"), the largest was " << max_observed_error;
1706 return interface_->ComputeExactConditionNumber();
1710 if (
var ==
nullptr)
return false;
1711 if (
var->index() >= 0 &&
var->index() <
static_cast<int>(variables_.size())) {
1713 return variables_[
var->index()] ==
var;
1719 std::string* model_str)
const {
1724 const auto status_or =
1726 *model_str = status_or.value_or(
"");
1727 return status_or.ok();
1731 std::string* model_str)
const {
1736 const auto status_or =
1738 *model_str = status_or.value_or(
"");
1739 return status_or.ok();
1743 for (
const auto& var_value_pair : hint) {
1745 <<
"hint variable does not belong to this solver";
1747 solution_hint_ = std::move(hint);
1750 void MPSolver::GenerateVariableNameIndex()
const {
1751 if (variable_name_to_index_)
return;
1752 variable_name_to_index_ = absl::flat_hash_map<std::string, int>();
1758 void MPSolver::GenerateConstraintNameIndex()
const {
1759 if (constraint_name_to_index_)
return;
1760 constraint_name_to_index_ = absl::flat_hash_map<std::string, int>();
1761 for (
const MPConstraint*
const cst : constraints_) {
1769 interface_->SetCallback(mp_callback);
1773 return interface_->SupportsCallbacks();
1777 absl::Mutex MPSolver::global_count_mutex_(absl::kConstInit);
1778 int64_t MPSolver::global_num_variables_ = 0;
1779 int64_t MPSolver::global_num_constraints_ = 0;
1784 absl::MutexLock lock(&global_count_mutex_);
1785 return global_num_variables_;
1791 absl::MutexLock lock(&global_count_mutex_);
1792 return global_num_constraints_;
1798 case MPSOLVER_OPTIMAL:
1799 case MPSOLVER_FEASIBLE:
1800 case MPSOLVER_INFEASIBLE:
1801 case MPSOLVER_NOT_SOLVED:
1802 case MPSOLVER_UNBOUNDED:
1803 case MPSOLVER_ABNORMAL:
1804 case MPSOLVER_UNKNOWN_STATUS:
1808 case MPSOLVER_MODEL_IS_VALID:
1809 case MPSOLVER_CANCELLED_BY_USER:
1812 case MPSOLVER_MODEL_INVALID:
1813 case MPSOLVER_MODEL_INVALID_SOLUTION_HINT:
1814 case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS:
1815 case MPSOLVER_SOLVER_TYPE_UNAVAILABLE:
1816 case MPSOLVER_INCOMPATIBLE_OPTIONS:
1820 <<
"MPSolverResponseStatusIsRpcError() called with invalid status "
1821 <<
"(value: " <<
status <<
")";
1833 sync_status_(MODEL_SYNCHRONIZED),
1836 last_constraint_index_(0),
1837 last_variable_index_(0),
1838 objective_value_(0.0),
1839 best_objective_bound_(0.0),
1845 LOG(WARNING) <<
"Writing model not implemented in this solver interface.";
1880 solver_->variable_is_extracted_.assign(
solver_->variables_.size(),
false);
1881 solver_->constraint_is_extracted_.assign(
solver_->constraints_.size(),
false);
1887 <<
"The model has been changed since the solution was last computed."
1888 <<
" MPSolverInterface::sync_status_ = " <<
sync_status_;
1899 LOG(DFATAL) <<
"No solution exists. MPSolverInterface::result_status_ = "
1912 const double trivial_worst_bound =
1913 maximize_ ? -std::numeric_limits<double>::infinity()
1914 : std::numeric_limits<double>::infinity();
1916 VLOG(1) <<
"Best objective bound only available for discrete problems.";
1917 return trivial_worst_bound;
1920 return trivial_worst_bound;
1923 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
1937 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for "
1938 << ProtoEnumToString<MPModelRequest::SolverType>(
1974 LOG(WARNING) <<
"Trying to set an unsupported parameter: " << param <<
".";
1978 LOG(WARNING) <<
"Trying to set an unsupported parameter: " << param <<
".";
1982 LOG(WARNING) <<
"Trying to set a supported parameter: " << param
1983 <<
" to an unsupported value: " <<
value;
1987 LOG(WARNING) <<
"Trying to set a supported parameter: " << param
1988 <<
" to an unsupported value: " <<
value;
1992 return absl::UnimplementedError(
1993 absl::StrFormat(
"SetNumThreads() not supported by %s.",
SolverVersion()));
2002 LOG(WARNING) <<
"SetSolverSpecificParametersAsString() not supported by "
2027 : relative_mip_gap_value_(kDefaultRelativeMipGap),
2029 dual_tolerance_value_(kDefaultDualTolerance),
2030 presolve_value_(kDefaultPresolve),
2031 scaling_value_(kDefaultIntegerParamValue),
2032 lp_algorithm_value_(kDefaultIntegerParamValue),
2033 incrementality_value_(kDefaultIncrementality),
2034 lp_algorithm_is_default_(true) {}
2040 relative_mip_gap_value_ =
value;
2044 primal_tolerance_value_ =
value;
2048 dual_tolerance_value_ =
value;
2052 LOG(ERROR) <<
"Trying to set an unknown parameter: " << param <<
".";
2062 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
2063 <<
" to an unknown value: " <<
value;
2065 presolve_value_ =
value;
2070 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
2071 <<
" to an unknown value: " <<
value;
2073 scaling_value_ =
value;
2078 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
2079 <<
" to an unknown value: " <<
value;
2081 lp_algorithm_value_ =
value;
2082 lp_algorithm_is_default_ =
false;
2087 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
2088 <<
" to an unknown value: " <<
value;
2090 incrementality_value_ =
value;
2094 LOG(ERROR) <<
"Trying to set an unknown parameter: " << param <<
".";
2115 LOG(ERROR) <<
"Trying to reset an unknown parameter: " << param <<
".";
2132 lp_algorithm_is_default_ =
true;
2140 LOG(ERROR) <<
"Trying to reset an unknown parameter: " << param <<
".";
2159 return relative_mip_gap_value_;
2162 return primal_tolerance_value_;
2165 return dual_tolerance_value_;
2168 LOG(ERROR) <<
"Trying to get an unknown parameter: " << param <<
".";
2178 return presolve_value_;
2182 return lp_algorithm_value_;
2185 return incrementality_value_;
2188 return scaling_value_;
2191 LOG(ERROR) <<
"Trying to get an unknown parameter: " << param <<
".";
void Add(const FpNumber &value)
LinearExpr models a quantity that is linear in the decision variables (MPVariable) of an optimization...
const absl::flat_hash_map< const MPVariable *, double > & terms() const
An expression of the form:
The class for constraints of a Mathematical Programming (MP) model.
void SetBounds(double lb, double ub)
Sets both the lower and upper bounds.
void SetCoefficient(const MPVariable *const var, double coeff)
Sets the coefficient of the variable on the constraint.
double GetCoefficient(const MPVariable *const var) const
Gets the coefficient of a given variable on the constraint (which is 0 if the variable does not appea...
double ub() const
Returns the upper bound.
const MPVariable * indicator_variable() const
bool indicator_value() const
void Clear()
Clears all variables and coefficients. Does not clear the bounds.
bool is_lazy() const
Advanced usage: returns true if the constraint is "lazy" (see below).
void set_is_lazy(bool laziness)
Advanced usage: sets the constraint "laziness".
double lb() const
Returns the lower bound.
const std::string & name() const
Returns the name of the constraint.
MPSolver::BasisStatus basis_status() const
Advanced usage: returns the basis status of the constraint.
double dual_value() const
Advanced usage: returns the dual value of the constraint in the current solution (only available for ...
A class to express a linear objective.
void SetCoefficient(const MPVariable *const var, double coeff)
Sets the coefficient of the variable in the objective.
double GetCoefficient(const MPVariable *const var) const
Gets the coefficient of a given variable in the objective.
void SetOffset(double value)
Sets the constant term in the objective.
bool maximization() const
Is the optimization direction set to maximize?
void OptimizeLinearExpr(const LinearExpr &linear_expr, bool is_maximization)
Resets the current objective to take the value of linear_expr, and sets the objective direction to ma...
void AddLinearExpr(const LinearExpr &linear_expr)
Adds linear_expr to the current objective, does not change the direction.
double Value() const
Returns the objective value of the best solution found so far.
double offset() const
Gets the constant term in the objective.
double BestBound() const
Returns the best objective bound.
bool minimization() const
Is the optimization direction set to minimize?
void Clear()
Clears the offset, all variables and coefficients, and the optimization direction.
void SetMinimization()
Sets the optimization direction to minimize.
void SetOptimizationDirection(bool maximize)
Sets the optimization direction (maximize: true or minimize: false).
This mathematical programming (MP) solver class is the main class though which users build and solve ...
void FillSolutionResponseProto(MPSolutionResponse *response) const
Encodes the current solution in a solution response protocol buffer.
int NumConstraints() const
Returns the number of constraints.
static int64_t global_num_constraints()
static OptimizationProblemType ParseSolverTypeOrDie(const std::string &solver_id)
Parses the name of the solver and returns the correct optimization type or dies.
const std::string & Name() const
Returns the name of the model set at construction.
MPConstraint * constraint(int index) const
Returns the constraint at the given index.
void MakeBoolVarArray(int nb, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of boolean variables.
MPObjective * MutableObjective()
Returns the mutable objective object.
bool VerifySolution(double tolerance, bool log_errors) const
Advanced usage: Verifies the correctness of the solution.
void Reset()
Advanced usage: resets extracted model to solve from scratch.
MPVariable * LookupVariableOrNull(const std::string &var_name) const
Looks up a variable by name, and returns nullptr if it does not exist.
int64_t iterations() const
Returns the number of simplex iterations.
void SetStartingLpBasis(const std::vector< MPSolver::BasisStatus > &variable_statuses, const std::vector< MPSolver::BasisStatus > &constraint_statuses)
Advanced usage: Incrementality.
static bool SupportsProblemType(OptimizationProblemType problem_type)
Whether the given problem type is supported (this will depend on the targets that you linked).
static MPSolver * CreateSolver(const std::string &solver_id)
Recommended factory method to create a MPSolver instance, especially in non C++ languages.
MPVariable * MakeBoolVar(const std::string &name)
Creates a boolean variable.
void SetHint(std::vector< std::pair< const MPVariable *, double > > hint)
Sets a hint for solution.
double ComputeExactConditionNumber() const
Advanced usage: computes the exact condition number of the current scaled basis: L1norm(B) * L1norm(i...
const MPObjective & Objective() const
Returns the objective object.
ResultStatus
The status of solving the problem.
@ FEASIBLE
feasible, or stopped by limit.
@ NOT_SOLVED
not been solved yet.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
@ MODEL_INVALID
the model is trivially invalid (NaN coefficients, etc).
static int64_t global_num_variables()
int64_t wall_time() const
void MakeNumVarArray(int nb, double lb, double ub, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of continuous variables.
void MakeVarArray(int nb, double lb, double ub, bool integer, const std::string &name_prefix, std::vector< MPVariable * > *vars)
Creates an array of variables.
void * underlying_solver()
Advanced usage: returns the underlying solver.
OptimizationProblemType
The type of problems (LP or MIP) that will be solved and the underlying solver (GLOP,...
@ GLOP_LINEAR_PROGRAMMING
@ CPLEX_MIXED_INTEGER_PROGRAMMING
@ KNAPSACK_MIXED_INTEGER_PROGRAMMING
@ XPRESS_LINEAR_PROGRAMMING
@ GLPK_LINEAR_PROGRAMMING
@ CPLEX_LINEAR_PROGRAMMING
@ GUROBI_LINEAR_PROGRAMMING
@ XPRESS_MIXED_INTEGER_PROGRAMMING
@ GUROBI_MIXED_INTEGER_PROGRAMMING
@ BOP_INTEGER_PROGRAMMING
@ SCIP_MIXED_INTEGER_PROGRAMMING
@ HIGHS_LINEAR_PROGRAMMING
@ PDLP_LINEAR_PROGRAMMING
@ SAT_INTEGER_PROGRAMMING
@ GLPK_MIXED_INTEGER_PROGRAMMING
@ CBC_MIXED_INTEGER_PROGRAMMING
@ HIGHS_MIXED_INTEGER_PROGRAMMING
bool SetSolverSpecificParametersAsString(const std::string ¶meters)
Advanced usage: pass solver specific parameters in text format.
absl::Status LoadSolutionFromProto(const MPSolutionResponse &response, double tolerance=std::numeric_limits< double >::infinity())
Load a solution encoded in a protocol buffer onto this solver for easy access via the MPSolver interf...
absl::Status SetNumThreads(int num_threads)
Sets the number of threads to use by the underlying solver.
std::string SolverVersion() const
Returns a string describing the underlying solver and its version.
bool SupportsCallbacks() const
void ExportModelToProto(MPModelProto *output_model) const
Exports model to protocol buffer.
void MakeIntVarArray(int nb, double lb, double ub, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of integer variables.
std::vector< double > ComputeConstraintActivities() const
Advanced usage: compute the "activities" of all constraints, which are the sums of their linear terms...
static double infinity()
Infinity.
static bool ParseSolverType(absl::string_view solver_id, OptimizationProblemType *type)
Parses the name of the solver.
int NumVariables() const
Returns the number of variables.
absl::Status ClampSolutionWithinBounds()
Resets values of out of bound variables to the corresponding bound and returns an error if any of the...
bool OwnsVariable(const MPVariable *var) const
int64_t nodes() const
Returns the number of branch-and-bound nodes evaluated during the solve.
void Clear()
Clears the objective (including the optimization direction), all variables and constraints.
bool ExportModelAsLpFormat(bool obfuscate, std::string *model_str) const
Shortcuts to the homonymous MPModelProtoExporter methods, via exporting to a MPModelProto with Export...
void Write(const std::string &file_name)
Writes the model using the solver internal write function.
static void SolveWithProto(const MPModelRequest &model_request, MPSolutionResponse *response, std::atomic< bool > *interrupt=nullptr)
Solves the model encoded by a MPModelRequest protocol buffer and fills the solution encoded as a MPSo...
MPConstraint * MakeRowConstraint()
Creates a constraint with -infinity and +infinity bounds.
void SetCallback(MPCallback *mp_callback)
MPSolverResponseStatus LoadModelFromProto(const MPModelProto &input_model, std::string *error_message)
Loads model from protocol buffer.
bool OutputIsEnabled() const
Controls (or queries) the amount of output produced by the underlying solver.
bool ExportModelAsMpsFormat(bool fixed_format, bool obfuscate, std::string *model_str) const
ABSL_MUST_USE_RESULT bool NextSolution()
Some solvers (MIP only, not LP) can produce multiple solutions to the problem.
MPVariable * MakeVar(double lb, double ub, bool integer, const std::string &name)
Creates a variable with the given bounds, integrality requirement and name.
MPConstraint * LookupConstraintOrNull(const std::string &constraint_name) const
Looks up a constraint by name, and returns nullptr if it does not exist.
MPVariable * MakeNumVar(double lb, double ub, const std::string &name)
Creates a continuous variable.
bool InterruptSolve()
Interrupts the Solve() execution to terminate processing if possible.
MPVariable * MakeIntVar(double lb, double ub, const std::string &name)
Creates an integer variable.
MPVariable * variable(int index) const
Returns the variable at position index.
MPSolver(const std::string &name, OptimizationProblemType problem_type)
Create a solver with the given name and underlying solver backend.
ResultStatus Solve()
Solves the problem using the default parameter values.
void EnableOutput()
Enables solver logging.
void SuppressOutput()
Suppresses solver logging.
static bool SolverTypeSupportsInterruption(const MPModelRequest::SolverType solver)
MPSolverResponseStatus LoadModelFromProtoWithUniqueNamesOrDie(const MPModelProto &input_model, std::string *error_message)
Loads model from protocol buffer.
virtual OptimizationProblemType ProblemType() const
Returns the optimization problem type set at construction.
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
void SetTimeLimit(absl::Duration time_limit)
virtual ~MPSolverInterface()
double best_objective_bound() const
virtual void SetLpAlgorithm(int value)=0
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
virtual void ExtractObjective()=0
void SetUnsupportedDoubleParam(MPSolverParameters::DoubleParam param)
virtual void ExtractNewVariables()=0
MPSolver::ResultStatus result_status_
static const int kDummyVariableIndex
void InvalidateSolutionSynchronization()
void SetMIPParameters(const MPSolverParameters ¶m)
int last_constraint_index_
virtual bool IsContinuous() const =0
virtual double ComputeExactConditionNumber() const
virtual void Write(const std::string &filename)
MPSolverInterface(MPSolver *const solver)
bool constraint_is_extracted(int ct_index) const
virtual void SetVariableBounds(int index, double lb, double ub)=0
virtual void SetPrimalTolerance(double value)=0
virtual void BranchingPriorityChangedForVariable(int var_index)
virtual void SetRelativeMipGap(double value)=0
double best_objective_bound_
virtual void SetOptimizationDirection(bool maximize)=0
virtual bool SetSolverSpecificParametersAsString(const std::string ¶meters)
virtual MPSolver::BasisStatus column_status(int variable_index) const =0
virtual void ExtractNewConstraints()=0
virtual MPSolver::BasisStatus row_status(int constraint_index) const =0
virtual std::string SolverVersion() const =0
virtual absl::Status SetNumThreads(int num_threads)
double objective_value() const
int last_variable_index() const
virtual void ClearConstraint(MPConstraint *const constraint)=0
bool CheckSolutionIsSynchronizedAndExists() const
bool CheckSolutionIsSynchronized() const
virtual bool CheckSolutionExists() const
virtual void SetObjectiveOffset(double value)=0
virtual void SetVariableInteger(int index, bool integer)=0
void ResetExtractionInformation()
virtual void ClearObjective()=0
bool variable_is_extracted(int var_index) const
virtual bool IsMIP() const =0
virtual void SetDualTolerance(double value)=0
virtual void SetPresolveMode(int value)=0
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
virtual void SetCoefficient(MPConstraint *const constraint, const MPVariable *const variable, double new_value, double old_value)=0
virtual void SetObjectiveCoefficient(const MPVariable *const variable, double coefficient)=0
void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param, double value)
virtual void SetConstraintBounds(int index, double lb, double ub)=0
void SetCommonParameters(const MPSolverParameters ¶m)
SynchronizationStatus sync_status_
This class stores parameter settings for LP and MIP solvers.
static const double kDefaultRelativeMipGap
static const int kUnknownIntegerParamValue
void ResetIntegerParam(MPSolverParameters::IntegerParam param)
Sets an integer parameter to its default value (default value defined in MPSolverParameters if it exi...
void SetDoubleParam(MPSolverParameters::DoubleParam param, double value)
Sets a double parameter to a specific value.
IncrementalityValues
Advanced usage: Incrementality options.
@ INCREMENTALITY_OFF
Start solve from scratch.
@ INCREMENTALITY_ON
Reuse results from previous solve as much as the underlying solver allows.
@ SCALING_ON
Scaling is on.
@ SCALING_OFF
Scaling is off.
static const IncrementalityValues kDefaultIncrementality
void Reset()
Sets all parameters to their default value.
DoubleParam
Enumeration of parameters that take continuous values.
@ DUAL_TOLERANCE
Advanced usage: tolerance for dual feasibility of basic solutions.
@ PRIMAL_TOLERANCE
Advanced usage: tolerance for primal feasibility of basic solutions.
@ RELATIVE_MIP_GAP
Limit for relative MIP gap.
static const PresolveValues kDefaultPresolve
double GetDoubleParam(MPSolverParameters::DoubleParam param) const
Returns the value of a double parameter.
static const double kDefaultDualTolerance
static const double kUnknownDoubleParamValue
IntegerParam
Enumeration of parameters that take integer or categorical values.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
@ PRESOLVE
Advanced usage: presolve mode.
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
@ BARRIER
Barrier algorithm.
PresolveValues
For each categorical parameter, enumeration of possible values.
@ PRESOLVE_ON
Presolve is on.
@ PRESOLVE_OFF
Presolve is off.
static const int kDefaultIntegerParamValue
static const double kDefaultPrimalTolerance
void SetIntegerParam(MPSolverParameters::IntegerParam param, int value)
Sets a integer parameter to a specific value.
static const double kDefaultDoubleParamValue
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
MPSolverParameters()
The constructor sets all parameters to their default value.
void ResetDoubleParam(MPSolverParameters::DoubleParam param)
Sets a double parameter to its default value (default value defined in MPSolverParameters if it exist...
The class for variables of a Mathematical Programming (MP) model.
void SetBounds(double lb, double ub)
Sets both the lower and upper bounds.
double unrounded_solution_value() const
Advanced usage: unrounded solution value.
void set_solution_value(double value)
void SetBranchingPriority(int priority)
double ub() const
Returns the upper bound.
double reduced_cost() const
Advanced usage: returns the reduced cost of the variable in the current solution (only available for ...
void SetInteger(bool integer)
Sets the integrality requirement of the variable.
bool integer() const
Returns the integrality requirement of the variable.
int index() const
Returns the index of the variable in the MPSolver::variables_.
double lb() const
Returns the lower bound.
const std::string & name() const
Returns the name of the variable.
double solution_value() const
Returns the value of the variable in the current solution.
MPSolver::BasisStatus basis_status() const
Advanced usage: returns the basis status of the variable in the current solution (only available for ...
virtual std::string name() const
Object naming.
void Schedule(std::function< void()> closure)
SharedResponseManager * response
ABSL_FLAG(bool, verify_solution, false, "Systematically verify the solution when calling Solve()" ", and change the return value of Solve() to ABNORMAL if" " an error was detected.")
MPSolver::OptimizationProblemType problem_type
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
void STLDeleteElements(T *container)
void InsertOrDie(Collection *const collection, const typename Collection::value_type &value)
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Collection of objects used to extend the Constraint Solver library.
MPSolverInterface * BuildGurobiInterface(bool mip, MPSolver *const solver)
MPSolverInterface * BuildSCIPInterface(MPSolver *const solver)
MPSolverInterface * BuildBopInterface(MPSolver *const solver)
constexpr double kDefaultPrimalTolerance
const absl::string_view ToString(MPSolver::OptimizationProblemType optimization_problem_type)
bool SolverTypeIsMip(MPModelRequest::SolverType solver_type)
MPSolverInterface * BuildCBCInterface(MPSolver *const solver)
bool AreWithinAbsoluteOrRelativeTolerances(FloatType x, FloatType y, FloatType relative_tolerance, FloatType absolute_tolerance)
absl::StatusOr< std::string > ExportModelAsMpsFormat(const MPModelProto &model, const MPModelExportOptions &options)
Outputs the current model (variables, constraints, objective) as a string encoded in MPS file format,...
bool AbslParseFlag(const absl::string_view text, MPSolver::OptimizationProblemType *solver_type, std::string *error)
std::optional< LazyMutableCopy< MPModelProto > > ExtractValidMPModelOrPopulateResponseStatus(const MPModelRequest &request, MPSolutionResponse *response)
If the model is valid and non-empty, returns it (possibly after extracting the model_delta).
std::string FindErrorInMPModelProto(const MPModelProto &model, double abs_value_threshold, const bool accept_trivially_infeasible_bounds)
Returns an empty string iff the model is valid and not trivially infeasible.
MPSolverInterface * BuildSatInterface(MPSolver *const solver)
MPSolverInterface * BuildCLPInterface(MPSolver *const solver)
MPSolverInterface * BuildPdlpInterface(MPSolver *const solver)
constexpr NamedOptimizationProblemType kOptimizationProblemTypeNames[]
MPSolverInterface * BuildGLOPInterface(MPSolver *const solver)
bool GurobiIsCorrectlyInstalled()
absl::StatusOr< std::string > ExportModelAsLpFormat(const MPModelProto &model, const MPModelExportOptions &options)
Outputs the current model (variables, constraints, objective) as a string encoded in the so-called "C...
bool MPSolverResponseStatusIsRpcError(MPSolverResponseStatus status)
const std::optional< Range > & range
bool obfuscate
Obfuscates variable and constraint names.
#define VLOG(verboselevel)