18 #if !defined(_MSC_VER)
26 #include "absl/status/status.h"
27 #include "absl/strings/ascii.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/str_format.h"
30 #include "absl/strings/str_replace.h"
31 #include "absl/synchronization/mutex.h"
47 "Systematically verify the solution when calling Solve()"
48 ", and change the return value of Solve() to ABNORMAL if"
49 " an error was detected.");
51 "If --verify_solution is set: LOG(ERROR) all errors detected"
52 " during the verification of the solution.");
54 "If set, enables verbose output for the solver. Setting this flag"
55 " is the same as calling MPSolver::EnableOutput().");
58 "If set, the user-provided Model won't be verified before Solve()."
59 " Invalid models will typically trigger various error responses"
60 " from the underlying solvers; sometimes crashes.");
65 switch (solver_type) {
66 case MPModelRequest::GLOP_LINEAR_PROGRAMMING:
67 case MPModelRequest::CLP_LINEAR_PROGRAMMING:
68 case MPModelRequest::GLPK_LINEAR_PROGRAMMING:
69 case MPModelRequest::GUROBI_LINEAR_PROGRAMMING:
70 case MPModelRequest::XPRESS_LINEAR_PROGRAMMING:
71 case MPModelRequest::CPLEX_LINEAR_PROGRAMMING:
74 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING:
75 case MPModelRequest::GLPK_MIXED_INTEGER_PROGRAMMING:
76 case MPModelRequest::CBC_MIXED_INTEGER_PROGRAMMING:
77 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING:
78 case MPModelRequest::KNAPSACK_MIXED_INTEGER_PROGRAMMING:
79 case MPModelRequest::BOP_INTEGER_PROGRAMMING:
80 case MPModelRequest::SAT_INTEGER_PROGRAMMING:
81 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING:
82 case MPModelRequest::CPLEX_MIXED_INTEGER_PROGRAMMING:
85 LOG(DFATAL) <<
"Invalid SolverType: " << solver_type;
91 if (
var ==
nullptr)
return 0.0;
97 if (
var ==
nullptr)
return;
99 auto it = coefficients_.find(
var);
107 if (it != coefficients_.end() && it->second != 0.0) {
108 const double old_value = it->second;
114 auto insertion_result = coefficients_.insert(std::make_pair(
var, coeff));
115 const double old_value =
116 insertion_result.second ? 0.0 : insertion_result.first->second;
117 insertion_result.first->second = coeff;
123 coefficients_.clear();
127 const bool change =
lb != lb_ ||
ub != ub_;
137 LOG(DFATAL) <<
"Dual value only available for continuous problems";
146 LOG(DFATAL) <<
"Basis status only available for continuous problems";
156 bool MPConstraint::ContainsNewVariables() {
158 for (
const auto& entry : coefficients_) {
159 const int variable_index = entry.first->index();
160 if (variable_index >= last_variable_index ||
172 if (
var ==
nullptr)
return 0.0;
178 if (
var ==
nullptr)
return;
180 auto it = coefficients_.find(
var);
183 if (it == coefficients_.end() || it->second == 0.0)
return;
186 coefficients_[
var] = coeff;
198 for (
auto var_value_pair : linear_expr.
terms()) {
200 <<
"Bad MPVariable* in LinearExpr, did you try adding an integer to an "
201 "MPVariable* directly?";
207 bool is_maximization) {
208 CheckLinearExpr(*interface_->
solver_, linear_expr);
210 coefficients_.clear();
212 for (
const auto& kv : linear_expr.
terms()) {
219 CheckLinearExpr(*interface_->
solver_, linear_expr);
221 for (
const auto& kv : linear_expr.
terms()) {
228 coefficients_.clear();
268 return (integer_ && interface_->
IsMIP()) ? round(solution_value_)
274 return solution_value_;
279 LOG(DFATAL) <<
"Reduced cost only available for continuous problems";
283 return reduced_cost_;
288 LOG(DFATAL) <<
"Basis status only available for continuous problems";
299 const bool change =
lb != lb_ ||
ub != ub_;
317 if (priority == branching_priority_)
return;
318 branching_priority_ = priority;
327 return interface_->SolverVersion();
335 if (num_threads < 1) {
336 return absl::InvalidArgumentError(
"num_threads must be a positive number.");
338 const absl::Status status = interface_->SetNumThreads(num_threads);
340 num_threads_ = num_threads;
347 solver_specific_parameter_string_ =
parameters;
348 return interface_->SetSolverSpecificParametersAsString(
parameters);
353 #if defined(USE_CLP) || defined(USE_CBC)
359 #if defined(USE_GLPK)
365 #if defined(USE_SCIP)
370 #if defined(USE_CPLEX)
375 #if defined(USE_XPRESS)
382 DCHECK(solver !=
nullptr);
390 #if defined(USE_GLPK)
392 return BuildGLPKInterface(
false, solver);
394 return BuildGLPKInterface(
true, solver);
396 #if defined(USE_CLP) || defined(USE_CBC)
404 #if defined(USE_SCIP)
412 #if defined(USE_CPLEX)
414 return BuildCplexInterface(
false, solver);
416 return BuildCplexInterface(
true, solver);
418 #if defined(USE_XPRESS)
420 return BuildXpressInterface(
true, solver);
422 return BuildXpressInterface(
false, solver);
426 LOG(FATAL) <<
"Linear solver not recognized.";
433 int NumDigits(
int n) {
436 #if defined(_MSC_VER)
437 return static_cast<int>(
std::max(1.0L, log(1.0L * n) / log(10.0L) + 1.0));
439 return static_cast<int>(
std::max(1.0, log10(
static_cast<double>(n)) + 1.0));
448 construction_time_(
absl::Now()) {
449 interface_.reset(BuildSolverInterface(
this));
450 if (FLAGS_linear_solver_enable_verbose_output) {
453 objective_.reset(
new MPObjective(interface_.get()));
474 return MPSolver::GurobiIsCorrectlyInstalled();
501 struct NamedOptimizationProblemType {
507 #if defined(_MSC_VER)
534 const std::string
id =
535 absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{
"-",
"_"}});
538 MPModelRequest::SolverType solver_type;
539 if (MPModelRequest::SolverType_Parse(
id, &solver_type)) {
545 std::string lower_id = absl::AsciiStrToLower(
id);
548 if (absl::EndsWith(lower_id,
"_mip")) {
549 lower_id = lower_id.substr(0, lower_id.size() - 4);
553 if (lower_id ==
"cp_sat") {
559 if (named_solver.name == lower_id) {
560 *type = named_solver.problem_type;
571 if (named_solver.problem_type == optimization_problem_type) {
572 return named_solver.name;
575 LOG(FATAL) <<
"Unrecognized solver type: "
576 <<
static_cast<int>(optimization_problem_type);
582 std::string* error) {
583 DCHECK(solver_type !=
nullptr);
584 DCHECK(error !=
nullptr);
587 *error = absl::StrCat(
"Solver type: ", text,
" does not exist.");
594 const std::string& solver_id) {
604 LOG(WARNING) <<
"Unrecognized solver type: " << solver_id;
608 LOG(WARNING) <<
"Support for " << solver_id
609 <<
" not linked in, or the license was not found.";
616 if (!variable_name_to_index_) GenerateVariableNameIndex();
618 absl::flat_hash_map<std::string, int>::const_iterator it =
619 variable_name_to_index_->find(var_name);
620 if (it == variable_name_to_index_->end())
return nullptr;
621 return variables_[it->second];
625 const std::string& constraint_name)
const {
626 if (!constraint_name_to_index_) GenerateConstraintNameIndex();
628 const auto it = constraint_name_to_index_->find(constraint_name);
629 if (it == constraint_name_to_index_->end())
return nullptr;
630 return constraints_[it->second];
636 const MPModelProto& input_model, std::string* error_message) {
641 return LoadModelFromProtoInternal(input_model,
true,
647 const MPModelProto& input_model, std::string* error_message) {
649 GenerateVariableNameIndex();
650 GenerateConstraintNameIndex();
652 return LoadModelFromProtoInternal(input_model,
false,
658 const MPModelProto& input_model,
bool clear_names,
659 bool check_model_validity, std::string* error_message) {
660 CHECK(error_message !=
nullptr);
661 if (check_model_validity) {
663 if (!error.empty()) {
664 *error_message = error;
666 <<
"Invalid model given to LoadModelFromProto(): " << error;
667 if (FLAGS_mpsolver_bypass_model_validation) {
669 <<
"Ignoring the model error(s) because of"
670 <<
" --mpsolver_bypass_model_validation.";
672 return error.find(
"Infeasible") == std::string::npos
679 if (input_model.has_quadratic_objective()) {
681 "Optimizing a quadratic objective is only supported through direct "
682 "proto solves. Please use MPSolver::SolveWithProto, or the solver's "
683 "direct proto solve function.";
689 const std::string empty;
690 for (
int i = 0; i < input_model.variable_size(); ++i) {
691 const MPVariableProto& var_proto = input_model.variable(i);
692 MPVariable* variable =
693 MakeNumVar(var_proto.lower_bound(), var_proto.upper_bound(),
694 clear_names ? empty : var_proto.name());
695 variable->SetInteger(var_proto.is_integer());
696 if (var_proto.branching_priority() != 0) {
697 variable->SetBranchingPriority(var_proto.branching_priority());
699 objective->SetCoefficient(variable, var_proto.objective_coefficient());
702 for (
const MPConstraintProto& ct_proto : input_model.constraint()) {
703 if (ct_proto.lower_bound() == -
infinity() &&
704 ct_proto.upper_bound() ==
infinity()) {
708 MPConstraint*
const ct =
710 clear_names ? empty : ct_proto.name());
711 ct->set_is_lazy(ct_proto.is_lazy());
712 for (
int j = 0; j < ct_proto.var_index_size(); ++j) {
713 ct->SetCoefficient(variables_[ct_proto.var_index(j)],
714 ct_proto.coefficient(j));
718 for (
const MPGeneralConstraintProto& general_constraint :
719 input_model.general_constraint()) {
720 switch (general_constraint.general_constraint_case()) {
721 case MPGeneralConstraintProto::kIndicatorConstraint: {
723 general_constraint.indicator_constraint().constraint();
730 MPConstraint*
const constraint =
new MPConstraint(
731 constraint_index,
proto.lower_bound(),
proto.upper_bound(),
732 clear_names ?
"" :
proto.name(), interface_.get());
733 if (constraint_name_to_index_) {
737 constraints_.push_back(constraint);
738 constraint_is_extracted_.push_back(
false);
740 constraint->set_is_lazy(
proto.is_lazy());
741 for (
int j = 0; j <
proto.var_index_size(); ++j) {
742 constraint->SetCoefficient(variables_[
proto.var_index(j)],
743 proto.coefficient(j));
746 MPVariable*
const variable =
747 variables_[general_constraint.indicator_constraint().var_index()];
748 constraint->indicator_variable_ = variable;
749 constraint->indicator_value_ =
750 general_constraint.indicator_constraint().var_value();
752 if (!interface_->AddIndicatorConstraint(constraint)) {
753 *error_message =
"Solver doesn't support indicator constraints";
759 *error_message = absl::StrFormat(
760 "Optimizing general constraints of type %i is only supported "
761 "through direct proto solves. Please use MPSolver::SolveWithProto, "
762 "or the solver's direct proto solve function.",
763 general_constraint.general_constraint_case());
768 objective->SetOptimizationDirection(input_model.maximize());
769 if (input_model.has_objective_offset()) {
770 objective->SetOffset(input_model.objective_offset());
774 solution_hint_.clear();
775 for (
int i = 0; i < input_model.solution_hint().var_index_size(); ++i) {
776 solution_hint_.push_back(
777 std::make_pair(variables_[input_model.solution_hint().var_index(i)],
778 input_model.solution_hint().var_value(i)));
810 ResultStatusToMPSolverResponseStatus(interface_->result_status_));
814 for (
int i = 0; i < variables_.size(); ++i) {
815 response->add_variable_value(variables_[i]->solution_value());
818 if (interface_->IsMIP()) {
819 response->set_best_objective_bound(interface_->best_objective_bound());
822 for (
int j = 0; j < constraints_.size(); ++j) {
823 response->add_dual_value(constraints_[j]->dual_value());
826 for (
int i = 0; i < variables_.size(); ++i) {
827 response->add_reduced_cost(variables_[i]->reduced_cost());
837 MPSolver solver(model_request.model().name(),
839 model_request.solver_type()));
840 if (model_request.enable_internal_solver_output()) {
844 auto optional_response = solver.interface_->DirectlySolveProto(model_request);
845 if (optional_response) {
846 *
response = std::move(optional_response).value();
850 const absl::optional<LazyMutableCopy<MPModelProto>> optional_model =
852 if (!optional_model) {
853 LOG_IF(WARNING, model_request.enable_internal_solver_output())
854 <<
"Failed to extract a valid model from protocol buffer. Status: "
855 << ProtoEnumToString<MPSolverResponseStatus>(
response->status()) <<
" ("
859 std::string error_message;
860 response->set_status(solver.LoadModelFromProtoInternal(
861 optional_model->get(),
true,
862 false, &error_message));
866 response->set_status_str(error_message);
867 LOG_IF(WARNING, model_request.enable_internal_solver_output())
868 <<
"LoadModelFromProtoInternal() failed even though the model was "
870 << ProtoEnumToString<MPSolverResponseStatus>(
response->status()) <<
" ("
871 <<
response->status() <<
"); Error: " << error_message;
874 if (model_request.has_solver_time_limit_seconds()) {
876 absl::Seconds(model_request.solver_time_limit_seconds()));
879 model_request.solver_specific_parameters());
885 DCHECK(output_model !=
nullptr);
886 output_model->Clear();
888 output_model->set_name(
Name());
890 for (
int j = 0; j < variables_.size(); ++j) {
892 MPVariableProto*
const variable_proto = output_model->add_variable();
895 variable_proto->set_name(
var->name());
896 variable_proto->set_lower_bound(
var->lb());
897 variable_proto->set_upper_bound(
var->ub());
898 variable_proto->set_is_integer(
var->integer());
899 if (objective_->GetCoefficient(
var) != 0.0) {
900 variable_proto->set_objective_coefficient(
901 objective_->GetCoefficient(
var));
903 if (
var->branching_priority() != 0) {
904 variable_proto->set_branching_priority(
var->branching_priority());
914 absl::flat_hash_map<const MPVariable*, int> var_to_index;
915 for (
int j = 0; j < variables_.size(); ++j) {
916 var_to_index[variables_[j]] = j;
920 for (
int i = 0; i < constraints_.size(); ++i) {
922 MPConstraintProto* constraint_proto;
924 MPGeneralConstraintProto*
const general_constraint_proto =
925 output_model->add_general_constraint();
926 general_constraint_proto->set_name(constraint->
name());
927 MPIndicatorConstraint*
const indicator_constraint_proto =
928 general_constraint_proto->mutable_indicator_constraint();
929 indicator_constraint_proto->set_var_index(
931 indicator_constraint_proto->set_var_value(constraint->
indicator_value());
932 constraint_proto = indicator_constraint_proto->mutable_constraint();
934 constraint_proto = output_model->add_constraint();
936 constraint_proto->set_name(constraint->
name());
937 constraint_proto->set_lower_bound(constraint->
lb());
938 constraint_proto->set_upper_bound(constraint->
ub());
939 constraint_proto->set_is_lazy(constraint->
is_lazy());
942 std::vector<std::pair<int, double>> linear_term;
943 for (
const auto& entry : constraint->coefficients_) {
946 DCHECK_NE(-1, var_index);
947 const double coeff = entry.second;
948 linear_term.push_back(std::pair<int, double>(var_index, coeff));
952 std::sort(linear_term.begin(), linear_term.end());
954 for (
const std::pair<int, double>& var_and_coeff : linear_term) {
955 constraint_proto->add_var_index(var_and_coeff.first);
956 constraint_proto->add_coefficient(var_and_coeff.second);
960 output_model->set_maximize(
Objective().maximization());
961 output_model->set_objective_offset(
Objective().offset());
963 if (!solution_hint_.empty()) {
964 PartialVariableAssignment*
const hint =
965 output_model->mutable_solution_hint();
966 for (
const auto& var_value_pair : solution_hint_) {
967 hint->add_var_index(var_value_pair.first->index());
968 hint->add_var_value(var_value_pair.second);
978 return absl::InvalidArgumentError(absl::StrCat(
979 "Cannot load a solution unless its status is OPTIMAL or FEASIBLE"
981 ProtoEnumToString<MPSolverResponseStatus>(
response.status()),
")"));
986 if (
response.variable_value_size() != variables_.size()) {
987 return absl::InvalidArgumentError(absl::StrCat(
988 "Trying to load a solution whose number of variables (",
990 ") does not correspond to the Solver's (", variables_.size(),
")"));
992 interface_->ExtractModel();
996 double largest_error = 0;
997 int num_vars_out_of_bounds = 0;
998 int last_offending_var = -1;
999 for (
int i = 0; i <
response.variable_value_size(); ++i) {
1000 const double var_value =
response.variable_value(i);
1003 const double lb_error =
var->lb() - var_value;
1004 const double ub_error = var_value -
var->ub();
1005 if (lb_error > tolerance || ub_error > tolerance) {
1006 ++num_vars_out_of_bounds;
1008 last_offending_var = i;
1011 if (num_vars_out_of_bounds > 0) {
1012 return absl::InvalidArgumentError(absl::StrCat(
1013 "Loaded a solution whose variables matched the solver's, but ",
1014 num_vars_out_of_bounds,
" of ", variables_.size(),
1015 " variables were out of their bounds, by more than the primal"
1016 " tolerance which is: ",
1017 tolerance,
". Max error: ", largest_error,
", last offender var is #",
1018 last_offending_var,
": '", variables_[last_offending_var]->name(),
1022 for (
int i = 0; i <
response.variable_value_size(); ++i) {
1023 variables_[i]->set_solution_value(
response.variable_value(i));
1027 if (
response.has_objective_value()) {
1028 interface_->objective_value_ =
response.objective_value();
1033 return absl::OkStatus();
1041 if (variable_name_to_index_) {
1042 variable_name_to_index_->clear();
1044 variable_is_extracted_.clear();
1045 constraints_.clear();
1046 if (constraint_name_to_index_) {
1047 constraint_name_to_index_->clear();
1049 constraint_is_extracted_.clear();
1050 interface_->Reset();
1051 solution_hint_.clear();
1059 const std::vector<BasisStatus>& variable_statuses,
1060 const std::vector<BasisStatus>& constraint_statuses) {
1061 interface_->SetStartingLpBasis(variable_statuses, constraint_statuses);
1065 const std::string&
name) {
1068 new MPVariable(var_index, lb, ub, integer,
name, interface_.get());
1069 if (variable_name_to_index_) {
1072 variables_.push_back(v);
1073 variable_is_extracted_.push_back(
false);
1074 interface_->AddVariable(v);
1079 const std::string&
name) {
1084 const std::string&
name) {
1093 const std::string&
name,
1094 std::vector<MPVariable*>* vars) {
1096 if (nb <= 0)
return;
1097 const int num_digits = NumDigits(nb);
1098 for (
int i = 0; i < nb; ++i) {
1103 absl::StrFormat(
"%s%0*d",
name.c_str(), num_digits, i);
1104 vars->push_back(
MakeVar(lb, ub, integer, vname));
1110 const std::string&
name,
1111 std::vector<MPVariable*>* vars) {
1116 const std::string&
name,
1117 std::vector<MPVariable*>* vars) {
1122 std::vector<MPVariable*>* vars) {
1135 const std::string&
name) {
1139 if (constraint_name_to_index_) {
1143 constraints_.push_back(constraint);
1144 constraint_is_extracted_.push_back(
false);
1145 interface_->AddRowConstraint(constraint);
1158 const std::string&
name) {
1168 int MPSolver::ComputeMaxConstraintSize(
int min_constraint_index,
1169 int max_constraint_index)
const {
1170 int max_constraint_size = 0;
1171 DCHECK_GE(min_constraint_index, 0);
1172 DCHECK_LE(max_constraint_index, constraints_.size());
1173 for (
int i = min_constraint_index; i < max_constraint_index; ++i) {
1175 if (
ct->coefficients_.size() > max_constraint_size) {
1176 max_constraint_size =
ct->coefficients_.size();
1179 return max_constraint_size;
1182 bool MPSolver::HasInfeasibleConstraints()
const {
1183 bool hasInfeasibleConstraints =
false;
1184 for (
int i = 0; i < constraints_.size(); ++i) {
1185 if (constraints_[i]->lb() > constraints_[i]->ub()) {
1186 LOG(WARNING) <<
"Constraint " << constraints_[i]->name() <<
" (" << i
1187 <<
") has contradictory bounds:"
1188 <<
" lower bound = " << constraints_[i]->lb()
1189 <<
" upper bound = " << constraints_[i]->ub();
1190 hasInfeasibleConstraints =
true;
1193 return hasInfeasibleConstraints;
1196 bool MPSolver::HasIntegerVariables()
const {
1197 for (
const MPVariable*
const variable : variables_) {
1198 if (variable->integer())
return true;
1205 return Solve(default_param);
1214 if (HasInfeasibleConstraints()) {
1216 return interface_->result_status_;
1220 if (FLAGS_verify_solution) {
1222 VLOG(1) <<
"--verify_solution enabled, but the solver did not find a"
1223 <<
" solution: skipping the verification.";
1226 FLAGS_log_verification_errors)) {
1228 interface_->result_status_ = status;
1231 DCHECK_EQ(interface_->result_status_, status);
1236 interface_->Write(file_name);
1241 const std::string prefix =
"Variable '" +
var.name() +
"': domain = ";
1244 return prefix +
"∅";
1248 if (
var.integer() &&
var.ub() -
var.lb() <= 1) {
1252 return prefix +
"∅";
1253 }
else if (lb == ub) {
1254 return absl::StrFormat(
"%s{ %d }", prefix.c_str(), lb);
1256 return absl::StrFormat(
"%s{ %d, %d }", prefix.c_str(), lb, ub);
1260 if (
var.lb() ==
var.ub()) {
1261 return absl::StrFormat(
"%s{ %f }", prefix.c_str(),
var.lb());
1263 return prefix + (
var.integer() ?
"Integer" :
"Real") +
" in " +
1265 ? std::string(
"]-∞")
1266 :
absl::StrFormat(
"[%f",
var.lb())) +
1268 (
var.ub() >= MPSolver::infinity() ? std::string(
"+∞[")
1269 :
absl::StrFormat(
"%f]",
var.ub()));
1272 std::string PrettyPrintConstraint(
const MPConstraint& constraint) {
1273 std::string prefix =
"Constraint '" + constraint.name() +
"': ";
1276 constraint.lb() > constraint.ub()) {
1277 return prefix +
"ALWAYS FALSE";
1281 return prefix +
"ALWAYS TRUE";
1283 prefix +=
"<linear expr>";
1285 if (constraint.lb() == constraint.ub()) {
1286 return absl::StrFormat(
"%s = %f", prefix.c_str(), constraint.lb());
1290 return absl::StrFormat(
"%s ≤ %f", prefix.c_str(), constraint.ub());
1293 return absl::StrFormat(
"%s ≥ %f", prefix.c_str(), constraint.lb());
1295 return absl::StrFormat(
"%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(),
1301 interface_->ExtractModel();
1302 for (
MPVariable*
const variable : variables_) {
1303 const double value = variable->solution_value();
1304 if (std::isnan(
value)) {
1305 return absl::InvalidArgumentError(
1306 absl::StrCat(
"NaN value for ", PrettyPrintVar(*variable)));
1308 if (value < variable->lb()) {
1309 variable->set_solution_value(variable->lb());
1310 }
else if (
value > variable->ub()) {
1311 variable->set_solution_value(variable->ub());
1315 return absl::OkStatus();
1320 if (!interface_->CheckSolutionIsSynchronizedAndExists())
return {};
1321 std::vector<double> activities(constraints_.size(), 0.0);
1322 for (
int i = 0; i < constraints_.size(); ++i) {
1325 for (
const auto& entry : constraint.coefficients_) {
1326 sum.
Add(entry.first->solution_value() * entry.second);
1328 activities[i] = sum.
Value();
1335 double max_observed_error = 0;
1336 if (tolerance < 0) tolerance =
infinity();
1340 for (
int i = 0; i < variables_.size(); ++i) {
1342 const double value =
var.solution_value();
1344 if (std::isnan(
value)) {
1347 LOG_IF(ERROR, log_errors) <<
"NaN value for " << PrettyPrintVar(
var);
1352 if (
value <
var.lb() - tolerance) {
1355 LOG_IF(ERROR, log_errors)
1356 <<
"Value " <<
value <<
" too low for " << PrettyPrintVar(
var);
1361 if (
value >
var.ub() + tolerance) {
1364 LOG_IF(ERROR, log_errors)
1365 <<
"Value " <<
value <<
" too high for " << PrettyPrintVar(
var);
1370 if (fabs(
value - round(
value)) > tolerance) {
1372 max_observed_error =
1374 LOG_IF(ERROR, log_errors)
1375 <<
"Non-integer value " <<
value <<
" for " << PrettyPrintVar(
var);
1379 if (!
IsMIP() && HasIntegerVariables()) {
1380 LOG_IF(INFO, log_errors) <<
"Skipped variable integrality check, because "
1381 <<
"a continuous relaxation of the model was "
1382 <<
"solved (i.e., the selected solver does not "
1383 <<
"support integer variables).";
1388 for (
int i = 0; i < constraints_.size(); ++i) {
1390 const double activity = activities[i];
1392 double inaccurate_activity = 0.0;
1393 for (
const auto& entry : constraint.coefficients_) {
1394 inaccurate_activity += entry.first->solution_value() * entry.second;
1397 if (std::isnan(activity) || std::isnan(inaccurate_activity)) {
1400 LOG_IF(ERROR, log_errors)
1401 <<
"NaN value for " << PrettyPrintConstraint(constraint);
1409 if (activity < constraint.
lb() - tolerance) {
1411 max_observed_error =
1412 std::max(max_observed_error, constraint.
lb() - activity);
1413 LOG_IF(ERROR, log_errors)
1414 <<
"Activity " << activity <<
" too low for "
1415 << PrettyPrintConstraint(constraint);
1416 }
else if (inaccurate_activity < constraint.
lb() - tolerance) {
1417 LOG_IF(WARNING, log_errors)
1418 <<
"Activity " << activity <<
", computed with the (inaccurate)"
1419 <<
" standard sum of its terms, is too low for "
1420 << PrettyPrintConstraint(constraint);
1424 if (activity > constraint.
ub() + tolerance) {
1426 max_observed_error =
1427 std::max(max_observed_error, activity - constraint.
ub());
1428 LOG_IF(ERROR, log_errors)
1429 <<
"Activity " << activity <<
" too high for "
1430 << PrettyPrintConstraint(constraint);
1431 }
else if (inaccurate_activity > constraint.
ub() + tolerance) {
1432 LOG_IF(WARNING, log_errors)
1433 <<
"Activity " << activity <<
", computed with the (inaccurate)"
1434 <<
" standard sum of its terms, is too high for "
1435 << PrettyPrintConstraint(constraint);
1445 double inaccurate_objective_value = objective.
offset();
1446 for (
const auto& entry : objective.coefficients_) {
1447 const double term = entry.first->solution_value() * entry.second;
1448 objective_sum.
Add(term);
1449 inaccurate_objective_value += term;
1451 const double actual_objective_value = objective_sum.
Value();
1453 objective.
Value(), actual_objective_value, tolerance, tolerance)) {
1456 max_observed_error, fabs(actual_objective_value - objective.
Value()));
1457 LOG_IF(ERROR, log_errors)
1458 <<
"Objective value " << objective.
Value() <<
" isn't accurate"
1459 <<
", it should be " << actual_objective_value
1460 <<
" (delta=" << actual_objective_value - objective.
Value() <<
").";
1462 inaccurate_objective_value,
1463 tolerance, tolerance)) {
1464 LOG_IF(WARNING, log_errors)
1465 <<
"Objective value " << objective.
Value() <<
" doesn't correspond"
1466 <<
" to the value computed with the standard (and therefore inaccurate)"
1467 <<
" sum of its terms.";
1469 if (num_errors > 0) {
1470 LOG_IF(ERROR, log_errors)
1471 <<
"There were " << num_errors <<
" errors above the tolerance ("
1472 << tolerance <<
"), the largest was " << max_observed_error;
1489 return interface_->ComputeExactConditionNumber();
1493 if (
var ==
nullptr)
return false;
1494 if (
var->index() >= 0 &&
var->index() < variables_.size()) {
1496 return variables_[
var->index()] ==
var;
1502 std::string* model_str)
const {
1507 const auto status_or =
1509 *model_str = status_or.value_or(
"");
1510 return status_or.ok();
1514 std::string* model_str)
const {
1524 const auto status_or =
1526 *model_str = status_or.value_or(
"");
1527 return status_or.ok();
1531 for (
const auto& var_value_pair : hint) {
1533 <<
"hint variable does not belong to this solver";
1535 solution_hint_ = std::move(hint);
1538 void MPSolver::GenerateVariableNameIndex()
const {
1539 if (variable_name_to_index_)
return;
1540 variable_name_to_index_ = absl::flat_hash_map<std::string, int>();
1546 void MPSolver::GenerateConstraintNameIndex()
const {
1547 if (constraint_name_to_index_)
return;
1548 constraint_name_to_index_ = absl::flat_hash_map<std::string, int>();
1549 for (
const MPConstraint*
const cst : constraints_) {
1557 interface_->SetCallback(mp_callback);
1561 return interface_->SupportsCallbacks();
1587 <<
"MPSolverResponseStatusIsRpcError() called with invalid status "
1588 <<
"(value: " << status <<
")";
1598 sync_status_(MODEL_SYNCHRONIZED),
1599 result_status_(
MPSolver::NOT_SOLVED),
1601 last_constraint_index_(0),
1602 last_variable_index_(0),
1603 objective_value_(0.0),
1609 LOG(WARNING) <<
"Writing model not implemented in this solver interface.";
1644 solver_->variable_is_extracted_.assign(
solver_->variables_.size(),
false);
1645 solver_->constraint_is_extracted_.assign(
solver_->constraints_.size(),
false);
1651 <<
"The model has been changed since the solution was last computed."
1652 <<
" MPSolverInterface::sync_status_ = " <<
sync_status_;
1663 LOG(DFATAL) <<
"No solution exists. MPSolverInterface::result_status_ = "
1675 LOG(DFATAL) <<
"No information is available for the best objective bound."
1683 return maximize_ ? -std::numeric_limits<double>::infinity()
1684 : std::numeric_limits<double>::infinity();
1700 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for "
1701 << ProtoEnumToString<MPModelRequest::SolverType>(
1702 static_cast<MPModelRequest::SolverType
>(
1737 LOG(WARNING) <<
"Trying to set an unsupported parameter: " << param <<
".";
1741 LOG(WARNING) <<
"Trying to set an unsupported parameter: " << param <<
".";
1745 LOG(WARNING) <<
"Trying to set a supported parameter: " << param
1746 <<
" to an unsupported value: " <<
value;
1750 LOG(WARNING) <<
"Trying to set a supported parameter: " << param
1751 <<
" to an unsupported value: " <<
value;
1755 return absl::UnimplementedError(
1756 absl::StrFormat(
"SetNumThreads() not supported by %s.",
SolverVersion()));
1773 std::string filename;
1775 filename += extension;
1776 if (no_error_so_far) {
1779 if (no_error_so_far) {
1784 LOG(DFATAL) <<
"Couldn't delete temporary parameters file: " << filename;
1787 if (!no_error_so_far) {
1788 LOG(WARNING) <<
"Error in SetSolverSpecificParametersAsString() "
1789 <<
"for solver type: "
1790 << ProtoEnumToString<MPModelRequest::SolverType>(
1791 static_cast<MPModelRequest::SolverType
>(
1794 return no_error_so_far;
1798 LOG(WARNING) <<
"ReadParameterFile() not supported by this solver.";
1826 : relative_mip_gap_value_(kDefaultRelativeMipGap),
1828 dual_tolerance_value_(kDefaultDualTolerance),
1829 presolve_value_(kDefaultPresolve),
1830 scaling_value_(kDefaultIntegerParamValue),
1831 lp_algorithm_value_(kDefaultIntegerParamValue),
1832 incrementality_value_(kDefaultIncrementality),
1833 lp_algorithm_is_default_(true) {}
1839 relative_mip_gap_value_ =
value;
1843 primal_tolerance_value_ =
value;
1847 dual_tolerance_value_ =
value;
1851 LOG(ERROR) <<
"Trying to set an unknown parameter: " << param <<
".";
1861 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
1862 <<
" to an unknown value: " <<
value;
1864 presolve_value_ =
value;
1869 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
1870 <<
" to an unknown value: " <<
value;
1872 scaling_value_ =
value;
1877 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
1878 <<
" to an unknown value: " <<
value;
1880 lp_algorithm_value_ =
value;
1881 lp_algorithm_is_default_ =
false;
1886 LOG(ERROR) <<
"Trying to set a supported parameter: " << param
1887 <<
" to an unknown value: " <<
value;
1889 incrementality_value_ =
value;
1893 LOG(ERROR) <<
"Trying to set an unknown parameter: " << param <<
".";
1914 LOG(ERROR) <<
"Trying to reset an unknown parameter: " << param <<
".";
1931 lp_algorithm_is_default_ =
true;
1939 LOG(ERROR) <<
"Trying to reset an unknown parameter: " << param <<
".";
1958 return relative_mip_gap_value_;
1961 return primal_tolerance_value_;
1964 return dual_tolerance_value_;
1967 LOG(ERROR) <<
"Trying to get an unknown parameter: " << param <<
".";
1977 return presolve_value_;
1981 return lp_algorithm_value_;
1984 return incrementality_value_;
1987 return scaling_value_;
1990 LOG(ERROR) <<
"Trying to get an unknown parameter: " << param <<
".";