26#include "absl/status/status.h"
27#include "absl/status/statusor.h"
28#include "absl/strings/ascii.h"
29#include "absl/strings/match.h"
30#include "absl/strings/str_cat.h"
31#include "absl/strings/str_format.h"
32#include "absl/strings/str_replace.h"
33#include "absl/synchronization/mutex.h"
41#include "ortools/linear_solver/linear_solver.pb.h"
48 "Systematically verify the solution when calling Solve()"
49 ", and change the return value of Solve() to ABNORMAL if"
50 " an error was detected.");
52 "If --verify_solution is set: LOG(ERROR) all errors detected"
53 " during the verification of the solution.");
54ABSL_FLAG(
bool, linear_solver_enable_verbose_output,
false,
55 "If set, enables verbose output for the solver. Setting this flag"
56 " is the same as calling MPSolver::EnableOutput().");
58ABSL_FLAG(
bool, mpsolver_bypass_model_validation,
false,
59 "If set, the user-provided Model won't be verified before Solve()."
60 " Invalid models will typically trigger various error responses"
61 " from the underlying solvers; sometimes crashes.");
66 switch (solver_type) {
67 case MPModelRequest::GLOP_LINEAR_PROGRAMMING:
68 case MPModelRequest::CLP_LINEAR_PROGRAMMING:
69 case MPModelRequest::GLPK_LINEAR_PROGRAMMING:
70 case MPModelRequest::GUROBI_LINEAR_PROGRAMMING:
71 case MPModelRequest::XPRESS_LINEAR_PROGRAMMING:
72 case MPModelRequest::CPLEX_LINEAR_PROGRAMMING:
75 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING:
76 case MPModelRequest::GLPK_MIXED_INTEGER_PROGRAMMING:
77 case MPModelRequest::CBC_MIXED_INTEGER_PROGRAMMING:
78 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING:
79 case MPModelRequest::KNAPSACK_MIXED_INTEGER_PROGRAMMING:
80 case MPModelRequest::BOP_INTEGER_PROGRAMMING:
81 case MPModelRequest::SAT_INTEGER_PROGRAMMING:
82 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING:
83 case MPModelRequest::CPLEX_MIXED_INTEGER_PROGRAMMING:
86 LOG(DFATAL) <<
"Invalid SolverType: " << solver_type;
92 if (
var ==
nullptr)
return 0.0;
98 if (
var ==
nullptr)
return;
100 auto it = coefficients_.find(
var);
108 if (it != coefficients_.end() && it->second != 0.0) {
109 const double old_value = it->second;
115 auto insertion_result = coefficients_.insert(std::make_pair(
var, coeff));
116 const double old_value =
117 insertion_result.second ? 0.0 : insertion_result.first->second;
118 insertion_result.first->second = coeff;
124 coefficients_.clear();
128 const bool change =
lb != lb_ ||
ub != ub_;
138 LOG(DFATAL) <<
"Dual value only available for continuous problems";
147 LOG(DFATAL) <<
"Basis status only available for continuous problems";
157bool MPConstraint::ContainsNewVariables() {
159 for (
const auto& entry : coefficients_) {
160 const int variable_index = entry.first->index();
161 if (variable_index >= last_variable_index ||
173 if (
var ==
nullptr)
return 0.0;
179 if (
var ==
nullptr)
return;
181 auto it = coefficients_.find(
var);
184 if (it == coefficients_.end() || it->second == 0.0)
return;
187 coefficients_[
var] = coeff;
199 for (
auto var_value_pair : linear_expr.
terms()) {
201 <<
"Bad MPVariable* in LinearExpr, did you try adding an integer to an "
202 "MPVariable* directly?";
208 bool is_maximization) {
209 CheckLinearExpr(*interface_->
solver_, linear_expr);
211 coefficients_.clear();
213 for (
const auto& kv : linear_expr.
terms()) {
220 CheckLinearExpr(*interface_->
solver_, linear_expr);
222 for (
const auto& kv : linear_expr.
terms()) {
229 coefficients_.clear();
269 return (integer_ && interface_->
IsMIP()) ? round(solution_value_)
275 return solution_value_;
280 LOG(DFATAL) <<
"Reduced cost only available for continuous problems";
284 return reduced_cost_;
289 LOG(DFATAL) <<
"Basis status only available for continuous problems";
300 const bool change =
lb != lb_ ||
ub != ub_;
318 if (priority == branching_priority_)
return;
319 branching_priority_ = priority;
328 return interface_->SolverVersion();
336 if (num_threads < 1) {
337 return absl::InvalidArgumentError(
"num_threads must be a positive number.");
339 const absl::Status status = interface_->SetNumThreads(num_threads);
341 num_threads_ = num_threads;
348 solver_specific_parameter_string_ =
parameters;
349 return interface_->SetSolverSpecificParametersAsString(
parameters);
354#if defined(USE_CLP) || defined(USE_CBC)
371#if defined(USE_CPLEX)
376#if defined(USE_XPRESS)
383 DCHECK(solver !=
nullptr);
393 return BuildGLPKInterface(
false, solver);
395 return BuildGLPKInterface(
true, solver);
397#if defined(USE_CLP) || defined(USE_CBC)
413#if defined(USE_CPLEX)
415 return BuildCplexInterface(
false, solver);
417 return BuildCplexInterface(
true, solver);
419#if defined(USE_XPRESS)
421 return BuildXpressInterface(
true, solver);
423 return BuildXpressInterface(
false, solver);
427 LOG(
FATAL) <<
"Linear solver not recognized.";
434int NumDigits(
int n) {
438 return static_cast<int>(
std::max(1.0L, log(1.0L * n) / log(10.0L) + 1.0));
440 return static_cast<int>(
std::max(1.0, log10(
static_cast<double>(n)) + 1.0));
449 construction_time_(
absl::Now()) {
450 interface_.reset(BuildSolverInterface(
this));
451 if (absl::GetFlag(FLAGS_linear_solver_enable_verbose_output)) {
454 objective_.reset(
new MPObjective(interface_.get()));
475 return MPSolver::GurobiIsCorrectlyInstalled();
502struct NamedOptimizationProblemType {
535 const std::string
id =
536 absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{
"-",
"_"}});
539 MPModelRequest::SolverType solver_type;
540 if (MPModelRequest::SolverType_Parse(
id, &solver_type)) {
546 std::string lower_id = absl::AsciiStrToLower(
id);
549 if (absl::EndsWith(lower_id,
"_mip")) {
550 lower_id = lower_id.substr(0, lower_id.size() - 4);
554 if (lower_id ==
"cp_sat") {
560 if (named_solver.name == lower_id) {
561 *type = named_solver.problem_type;
572 if (named_solver.problem_type == optimization_problem_type) {
573 return named_solver.name;
576 LOG(
FATAL) <<
"Unrecognized solver type: "
577 <<
static_cast<int>(optimization_problem_type);
583 std::string* error) {
584 DCHECK(solver_type !=
nullptr);
588 *error = absl::StrCat(
"Solver type: ", text,
" does not exist.");
595 const std::string& solver_id) {
605 LOG(
WARNING) <<
"Unrecognized solver type: " << solver_id;
610 <<
" not linked in, or the license was not found.";
617 if (!variable_name_to_index_) GenerateVariableNameIndex();
619 absl::flat_hash_map<std::string, int>::const_iterator it =
620 variable_name_to_index_->find(var_name);
621 if (it == variable_name_to_index_->end())
return nullptr;
622 return variables_[it->second];
626 const std::string& constraint_name)
const {
627 if (!constraint_name_to_index_) GenerateConstraintNameIndex();
629 const auto it = constraint_name_to_index_->find(constraint_name);
630 if (it == constraint_name_to_index_->end())
return nullptr;
631 return constraints_[it->second];
637 const MPModelProto& input_model, std::string* error_message) {
644 return LoadModelFromProtoInternal(input_model,
true,
650 const MPModelProto& input_model, std::string* error_message) {
654 GenerateVariableNameIndex();
655 GenerateConstraintNameIndex();
657 return LoadModelFromProtoInternal(input_model,
false,
662MPSolverResponseStatus MPSolver::LoadModelFromProtoInternal(
663 const MPModelProto& input_model,
bool clear_names,
664 bool check_model_validity, std::string* error_message) {
665 CHECK(error_message !=
nullptr);
666 if (check_model_validity) {
668 if (!error.empty()) {
669 *error_message = error;
671 <<
"Invalid model given to LoadModelFromProto(): " << error;
672 if (absl::GetFlag(FLAGS_mpsolver_bypass_model_validation)) {
674 <<
"Ignoring the model error(s) because of"
675 <<
" --mpsolver_bypass_model_validation.";
677 return absl::StrContains(error,
"Infeasible") ? MPSOLVER_INFEASIBLE
678 : MPSOLVER_MODEL_INVALID;
683 if (input_model.has_quadratic_objective()) {
685 "Optimizing a quadratic objective is only supported through direct "
686 "proto solves. Please use MPSolver::SolveWithProto, or the solver's "
687 "direct proto solve function.";
688 return MPSOLVER_MODEL_INVALID;
693 const std::string empty;
694 for (
int i = 0; i < input_model.variable_size(); ++i) {
695 const MPVariableProto& var_proto = input_model.variable(i);
696 MPVariable* variable =
697 MakeNumVar(var_proto.lower_bound(), var_proto.upper_bound(),
698 clear_names ? empty : var_proto.name());
699 variable->SetInteger(var_proto.is_integer());
700 if (var_proto.branching_priority() != 0) {
701 variable->SetBranchingPriority(var_proto.branching_priority());
703 objective->SetCoefficient(variable, var_proto.objective_coefficient());
706 for (
const MPConstraintProto& ct_proto : input_model.constraint()) {
707 if (ct_proto.lower_bound() == -
infinity() &&
708 ct_proto.upper_bound() ==
infinity()) {
712 MPConstraint*
const ct =
714 clear_names ? empty : ct_proto.name());
715 ct->set_is_lazy(ct_proto.is_lazy());
716 for (
int j = 0; j < ct_proto.var_index_size(); ++j) {
717 ct->SetCoefficient(variables_[ct_proto.var_index(j)],
718 ct_proto.coefficient(j));
722 for (
const MPGeneralConstraintProto& general_constraint :
723 input_model.general_constraint()) {
724 switch (general_constraint.general_constraint_case()) {
725 case MPGeneralConstraintProto::kIndicatorConstraint: {
727 general_constraint.indicator_constraint().constraint();
734 MPConstraint*
const constraint =
new MPConstraint(
735 constraint_index,
proto.lower_bound(),
proto.upper_bound(),
736 clear_names ?
"" :
proto.name(), interface_.get());
737 if (constraint_name_to_index_) {
741 constraints_.push_back(constraint);
742 constraint_is_extracted_.push_back(
false);
744 constraint->set_is_lazy(
proto.is_lazy());
745 for (
int j = 0; j <
proto.var_index_size(); ++j) {
746 constraint->SetCoefficient(variables_[
proto.var_index(j)],
747 proto.coefficient(j));
750 MPVariable*
const variable =
751 variables_[general_constraint.indicator_constraint().var_index()];
752 constraint->indicator_variable_ = variable;
753 constraint->indicator_value_ =
754 general_constraint.indicator_constraint().var_value();
756 if (!interface_->AddIndicatorConstraint(constraint)) {
757 *error_message =
"Solver doesn't support indicator constraints";
758 return MPSOLVER_MODEL_INVALID;
763 *error_message = absl::StrFormat(
764 "Optimizing general constraints of type %i is only supported "
765 "through direct proto solves. Please use MPSolver::SolveWithProto, "
766 "or the solver's direct proto solve function.",
767 general_constraint.general_constraint_case());
768 return MPSOLVER_MODEL_INVALID;
772 objective->SetOptimizationDirection(input_model.maximize());
773 if (input_model.has_objective_offset()) {
774 objective->SetOffset(input_model.objective_offset());
778 solution_hint_.clear();
779 for (
int i = 0; i < input_model.solution_hint().var_index_size(); ++i) {
780 solution_hint_.push_back(
781 std::make_pair(variables_[input_model.solution_hint().var_index(i)],
782 input_model.solution_hint().var_value(i)));
784 return MPSOLVER_MODEL_IS_VALID;
788MPSolverResponseStatus ResultStatusToMPSolverResponseStatus(
792 return MPSOLVER_OPTIMAL;
794 return MPSOLVER_FEASIBLE;
796 return MPSOLVER_INFEASIBLE;
798 return MPSOLVER_UNBOUNDED;
800 return MPSOLVER_ABNORMAL;
802 return MPSOLVER_MODEL_INVALID;
804 return MPSOLVER_NOT_SOLVED;
806 return MPSOLVER_UNKNOWN_STATUS;
814 ResultStatusToMPSolverResponseStatus(interface_->result_status_));
818 for (
int i = 0; i < variables_.size(); ++i) {
819 response->add_variable_value(variables_[i]->solution_value());
822 if (interface_->IsMIP()) {
823 response->set_best_objective_bound(interface_->best_objective_bound());
826 for (
int j = 0; j < constraints_.size(); ++j) {
827 response->add_dual_value(constraints_[j]->dual_value());
830 for (
int i = 0; i < variables_.size(); ++i) {
831 response->add_reduced_cost(variables_[i]->reduced_cost());
841 MPSolver solver(model_request.model().name(),
843 model_request.solver_type()));
844 if (model_request.enable_internal_solver_output()) {
848 auto optional_response = solver.interface_->DirectlySolveProto(model_request);
849 if (optional_response) {
850 *
response = std::move(optional_response).value();
854 const absl::optional<LazyMutableCopy<MPModelProto>> optional_model =
856 if (!optional_model) {
857 LOG_IF(
WARNING, model_request.enable_internal_solver_output())
858 <<
"Failed to extract a valid model from protocol buffer. Status: "
859 << ProtoEnumToString<MPSolverResponseStatus>(
response->status()) <<
" ("
863 std::string error_message;
864 response->set_status(solver.LoadModelFromProtoInternal(
865 optional_model->get(),
true,
866 false, &error_message));
869 if (
response->status() != MPSOLVER_MODEL_IS_VALID) {
870 response->set_status_str(error_message);
871 LOG_IF(
WARNING, model_request.enable_internal_solver_output())
872 <<
"LoadModelFromProtoInternal() failed even though the model was "
874 << ProtoEnumToString<MPSolverResponseStatus>(
response->status()) <<
" ("
875 <<
response->status() <<
"); Error: " << error_message;
878 if (model_request.has_solver_time_limit_seconds()) {
880 absl::Seconds(model_request.solver_time_limit_seconds()));
882 std::string warning_message;
883 if (model_request.has_solver_specific_parameters()) {
885 model_request.solver_specific_parameters())) {
886 if (model_request.ignore_solver_specific_parameters_failure()) {
889 "Warning: the solver specific parameters were not successfully "
892 response->set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
899 if (!warning_message.empty()) {
900 response->set_status_str(absl::StrCat(
907 DCHECK(output_model !=
nullptr);
908 output_model->Clear();
910 output_model->set_name(
Name());
912 for (
int j = 0; j < variables_.size(); ++j) {
914 MPVariableProto*
const variable_proto = output_model->add_variable();
917 variable_proto->set_name(
var->name());
918 variable_proto->set_lower_bound(
var->lb());
919 variable_proto->set_upper_bound(
var->ub());
920 variable_proto->set_is_integer(
var->integer());
921 if (objective_->GetCoefficient(
var) != 0.0) {
922 variable_proto->set_objective_coefficient(
923 objective_->GetCoefficient(
var));
925 if (
var->branching_priority() != 0) {
926 variable_proto->set_branching_priority(
var->branching_priority());
936 absl::flat_hash_map<const MPVariable*, int> var_to_index;
937 for (
int j = 0; j < variables_.size(); ++j) {
938 var_to_index[variables_[j]] = j;
942 for (
int i = 0; i < constraints_.size(); ++i) {
944 MPConstraintProto* constraint_proto;
946 MPGeneralConstraintProto*
const general_constraint_proto =
947 output_model->add_general_constraint();
948 general_constraint_proto->set_name(constraint->
name());
949 MPIndicatorConstraint*
const indicator_constraint_proto =
950 general_constraint_proto->mutable_indicator_constraint();
951 indicator_constraint_proto->set_var_index(
953 indicator_constraint_proto->set_var_value(constraint->
indicator_value());
954 constraint_proto = indicator_constraint_proto->mutable_constraint();
956 constraint_proto = output_model->add_constraint();
958 constraint_proto->set_name(constraint->
name());
959 constraint_proto->set_lower_bound(constraint->
lb());
960 constraint_proto->set_upper_bound(constraint->
ub());
961 constraint_proto->set_is_lazy(constraint->
is_lazy());
964 std::vector<std::pair<int, double>> linear_term;
965 for (
const auto& entry : constraint->coefficients_) {
969 const double coeff = entry.second;
970 linear_term.push_back(std::pair<int, double>(var_index, coeff));
974 std::sort(linear_term.begin(), linear_term.end());
976 for (
const std::pair<int, double>& var_and_coeff : linear_term) {
977 constraint_proto->add_var_index(var_and_coeff.first);
978 constraint_proto->add_coefficient(var_and_coeff.second);
982 output_model->set_maximize(
Objective().maximization());
983 output_model->set_objective_offset(
Objective().offset());
985 if (!solution_hint_.empty()) {
986 PartialVariableAssignment*
const hint =
987 output_model->mutable_solution_hint();
988 for (
const auto& var_value_pair : solution_hint_) {
989 hint->add_var_index(var_value_pair.first->index());
990 hint->add_var_value(var_value_pair.second);
998 if (
response.status() != MPSOLVER_OPTIMAL &&
999 response.status() != MPSOLVER_FEASIBLE) {
1000 return absl::InvalidArgumentError(absl::StrCat(
1001 "Cannot load a solution unless its status is OPTIMAL or FEASIBLE"
1003 ProtoEnumToString<MPSolverResponseStatus>(
response.status()),
")"));
1008 if (
response.variable_value_size() != variables_.size()) {
1009 return absl::InvalidArgumentError(absl::StrCat(
1010 "Trying to load a solution whose number of variables (",
1012 ") does not correspond to the Solver's (", variables_.size(),
")"));
1014 interface_->ExtractModel();
1018 double largest_error = 0;
1019 int num_vars_out_of_bounds = 0;
1020 int last_offending_var = -1;
1021 for (
int i = 0; i <
response.variable_value_size(); ++i) {
1022 const double var_value =
response.variable_value(i);
1025 const double lb_error =
var->lb() - var_value;
1026 const double ub_error = var_value -
var->ub();
1027 if (lb_error > tolerance || ub_error > tolerance) {
1028 ++num_vars_out_of_bounds;
1030 last_offending_var = i;
1033 if (num_vars_out_of_bounds > 0) {
1034 return absl::InvalidArgumentError(absl::StrCat(
1035 "Loaded a solution whose variables matched the solver's, but ",
1036 num_vars_out_of_bounds,
" of ", variables_.size(),
1037 " variables were out of their bounds, by more than the primal"
1038 " tolerance which is: ",
1039 tolerance,
". Max error: ", largest_error,
", last offender var is #",
1040 last_offending_var,
": '", variables_[last_offending_var]->name(),
1045 for (
int i = 0; i <
response.variable_value_size(); ++i) {
1046 variables_[i]->set_solution_value(
response.variable_value(i));
1050 if (
response.has_objective_value()) {
1051 interface_->objective_value_ =
response.objective_value();
1053 if (
response.has_best_objective_bound()) {
1054 interface_->best_objective_bound_ =
response.best_objective_bound();
1059 return absl::OkStatus();
1067 if (variable_name_to_index_) {
1068 variable_name_to_index_->clear();
1070 variable_is_extracted_.clear();
1071 constraints_.clear();
1072 if (constraint_name_to_index_) {
1073 constraint_name_to_index_->clear();
1075 constraint_is_extracted_.clear();
1076 interface_->Reset();
1077 solution_hint_.clear();
1085 const std::vector<BasisStatus>& variable_statuses,
1086 const std::vector<BasisStatus>& constraint_statuses) {
1087 interface_->SetStartingLpBasis(variable_statuses, constraint_statuses);
1091 const std::string&
name) {
1094 new MPVariable(var_index, lb, ub, integer,
name, interface_.get());
1095 if (variable_name_to_index_) {
1098 variables_.push_back(v);
1099 variable_is_extracted_.push_back(
false);
1100 interface_->AddVariable(v);
1105 const std::string&
name) {
1110 const std::string&
name) {
1119 const std::string&
name,
1120 std::vector<MPVariable*>* vars) {
1122 if (nb <= 0)
return;
1123 const int num_digits = NumDigits(nb);
1124 for (
int i = 0; i < nb; ++i) {
1129 absl::StrFormat(
"%s%0*d",
name.c_str(), num_digits, i);
1130 vars->push_back(
MakeVar(lb, ub, integer, vname));
1136 const std::string&
name,
1137 std::vector<MPVariable*>* vars) {
1142 const std::string&
name,
1143 std::vector<MPVariable*>* vars) {
1148 std::vector<MPVariable*>* vars) {
1161 const std::string&
name) {
1165 if (constraint_name_to_index_) {
1169 constraints_.push_back(constraint);
1170 constraint_is_extracted_.push_back(
false);
1171 interface_->AddRowConstraint(constraint);
1184 const std::string&
name) {
1194int MPSolver::ComputeMaxConstraintSize(
int min_constraint_index,
1195 int max_constraint_index)
const {
1196 int max_constraint_size = 0;
1198 DCHECK_LE(max_constraint_index, constraints_.size());
1199 for (
int i = min_constraint_index; i < max_constraint_index; ++i) {
1201 if (
ct->coefficients_.size() > max_constraint_size) {
1202 max_constraint_size =
ct->coefficients_.size();
1205 return max_constraint_size;
1208bool MPSolver::HasInfeasibleConstraints()
const {
1209 bool hasInfeasibleConstraints =
false;
1210 for (
int i = 0; i < constraints_.size(); ++i) {
1211 if (constraints_[i]->lb() > constraints_[i]->ub()) {
1212 LOG(
WARNING) <<
"Constraint " << constraints_[i]->name() <<
" (" << i
1213 <<
") has contradictory bounds:"
1214 <<
" lower bound = " << constraints_[i]->lb()
1215 <<
" upper bound = " << constraints_[i]->ub();
1216 hasInfeasibleConstraints =
true;
1219 return hasInfeasibleConstraints;
1222bool MPSolver::HasIntegerVariables()
const {
1223 for (
const MPVariable*
const variable : variables_) {
1224 if (variable->integer())
return true;
1231 return Solve(default_param);
1240 if (HasInfeasibleConstraints()) {
1242 return interface_->result_status_;
1246 if (absl::GetFlag(FLAGS_verify_solution)) {
1248 VLOG(1) <<
"--verify_solution enabled, but the solver did not find a"
1249 <<
" solution: skipping the verification.";
1252 absl::GetFlag(FLAGS_log_verification_errors))) {
1254 interface_->result_status_ = status;
1257 DCHECK_EQ(interface_->result_status_, status);
1262 interface_->Write(file_name);
1267 const std::string prefix =
"Variable '" +
var.
name() +
"': domain = ";
1270 return prefix +
"∅";
1274 if (
var.integer() &&
var.ub() -
var.lb() <= 1) {
1278 return prefix +
"∅";
1279 }
else if (lb == ub) {
1280 return absl::StrFormat(
"%s{ %d }", prefix.c_str(), lb);
1282 return absl::StrFormat(
"%s{ %d, %d }", prefix.c_str(), lb, ub);
1286 if (
var.lb() ==
var.ub()) {
1287 return absl::StrFormat(
"%s{ %f }", prefix.c_str(),
var.lb());
1289 return prefix + (
var.integer() ?
"Integer" :
"Real") +
" in " +
1291 ? std::string(
"]-∞")
1292 :
absl::StrFormat(
"[%f",
var.lb())) +
1294 (
var.ub() >= MPSolver::infinity() ?
std::string(
"+∞[")
1295 :
absl::StrFormat(
"%f]",
var.ub()));
1298std::string PrettyPrintConstraint(
const MPConstraint& constraint) {
1299 std::string prefix =
"Constraint '" + constraint.name() +
"': ";
1302 constraint.lb() > constraint.ub()) {
1303 return prefix +
"ALWAYS FALSE";
1307 return prefix +
"ALWAYS TRUE";
1309 prefix +=
"<linear expr>";
1311 if (constraint.lb() == constraint.ub()) {
1312 return absl::StrFormat(
"%s = %f", prefix.c_str(), constraint.lb());
1316 return absl::StrFormat(
"%s ≤ %f", prefix.c_str(), constraint.ub());
1319 return absl::StrFormat(
"%s ≥ %f", prefix.c_str(), constraint.lb());
1321 return absl::StrFormat(
"%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(),
1327 interface_->ExtractModel();
1328 for (
MPVariable*
const variable : variables_) {
1329 const double value = variable->solution_value();
1330 if (std::isnan(
value)) {
1331 return absl::InvalidArgumentError(
1332 absl::StrCat(
"NaN value for ", PrettyPrintVar(*variable)));
1334 if (value < variable->lb()) {
1335 variable->set_solution_value(variable->lb());
1336 }
else if (
value > variable->ub()) {
1337 variable->set_solution_value(variable->ub());
1341 return absl::OkStatus();
1346 if (!interface_->CheckSolutionIsSynchronizedAndExists())
return {};
1347 std::vector<double> activities(constraints_.size(), 0.0);
1348 for (
int i = 0; i < constraints_.size(); ++i) {
1351 for (
const auto& entry : constraint.coefficients_) {
1352 sum.
Add(entry.first->solution_value() * entry.second);
1354 activities[i] = sum.
Value();
1361 double max_observed_error = 0;
1362 if (tolerance < 0) tolerance =
infinity();
1366 for (
int i = 0; i < variables_.size(); ++i) {
1368 const double value =
var.solution_value();
1370 if (std::isnan(
value)) {
1373 LOG_IF(
ERROR, log_errors) <<
"NaN value for " << PrettyPrintVar(
var);
1378 if (
value <
var.lb() - tolerance) {
1382 <<
"Value " <<
value <<
" too low for " << PrettyPrintVar(
var);
1387 if (
value >
var.ub() + tolerance) {
1391 <<
"Value " <<
value <<
" too high for " << PrettyPrintVar(
var);
1396 if (fabs(
value - round(
value)) > tolerance) {
1398 max_observed_error =
1401 <<
"Non-integer value " <<
value <<
" for " << PrettyPrintVar(
var);
1405 if (!
IsMIP() && HasIntegerVariables()) {
1406 LOG_IF(
INFO, log_errors) <<
"Skipped variable integrality check, because "
1407 <<
"a continuous relaxation of the model was "
1408 <<
"solved (i.e., the selected solver does not "
1409 <<
"support integer variables).";
1414 for (
int i = 0; i < constraints_.size(); ++i) {
1416 const double activity = activities[i];
1418 double inaccurate_activity = 0.0;
1419 for (
const auto& entry : constraint.coefficients_) {
1420 inaccurate_activity += entry.first->solution_value() * entry.second;
1423 if (std::isnan(activity) || std::isnan(inaccurate_activity)) {
1427 <<
"NaN value for " << PrettyPrintConstraint(constraint);
1435 if (activity < constraint.
lb() - tolerance) {
1437 max_observed_error =
1438 std::max(max_observed_error, constraint.
lb() - activity);
1440 <<
"Activity " << activity <<
" too low for "
1441 << PrettyPrintConstraint(constraint);
1442 }
else if (inaccurate_activity < constraint.
lb() - tolerance) {
1444 <<
"Activity " << activity <<
", computed with the (inaccurate)"
1445 <<
" standard sum of its terms, is too low for "
1446 << PrettyPrintConstraint(constraint);
1450 if (activity > constraint.
ub() + tolerance) {
1452 max_observed_error =
1453 std::max(max_observed_error, activity - constraint.
ub());
1455 <<
"Activity " << activity <<
" too high for "
1456 << PrettyPrintConstraint(constraint);
1457 }
else if (inaccurate_activity > constraint.
ub() + tolerance) {
1459 <<
"Activity " << activity <<
", computed with the (inaccurate)"
1460 <<
" standard sum of its terms, is too high for "
1461 << PrettyPrintConstraint(constraint);
1471 double inaccurate_objective_value = objective.
offset();
1472 for (
const auto& entry : objective.coefficients_) {
1473 const double term = entry.first->solution_value() * entry.second;
1474 objective_sum.
Add(term);
1475 inaccurate_objective_value += term;
1477 const double actual_objective_value = objective_sum.
Value();
1479 objective.
Value(), actual_objective_value, tolerance, tolerance)) {
1482 max_observed_error, fabs(actual_objective_value - objective.
Value()));
1484 <<
"Objective value " << objective.
Value() <<
" isn't accurate"
1485 <<
", it should be " << actual_objective_value
1486 <<
" (delta=" << actual_objective_value - objective.
Value() <<
").";
1488 inaccurate_objective_value,
1489 tolerance, tolerance)) {
1491 <<
"Objective value " << objective.
Value() <<
" doesn't correspond"
1492 <<
" to the value computed with the standard (and therefore inaccurate)"
1493 <<
" sum of its terms.";
1495 if (num_errors > 0) {
1497 <<
"There were " << num_errors <<
" errors above the tolerance ("
1498 << tolerance <<
"), the largest was " << max_observed_error;
1515 return interface_->ComputeExactConditionNumber();
1519 if (
var ==
nullptr)
return false;
1520 if (
var->index() >= 0 &&
var->index() < variables_.size()) {
1522 return variables_[
var->index()] ==
var;
1528 std::string* model_str)
const {
1533 const auto status_or =
1535 *model_str = status_or.value_or(
"");
1536 return status_or.ok();
1540 std::string* model_str)
const {
1550 const auto status_or =
1552 *model_str = status_or.value_or(
"");
1553 return status_or.ok();
1557 for (
const auto& var_value_pair : hint) {
1559 <<
"hint variable does not belong to this solver";
1561 solution_hint_ = std::move(hint);
1564void MPSolver::GenerateVariableNameIndex()
const {
1565 if (variable_name_to_index_)
return;
1566 variable_name_to_index_ = absl::flat_hash_map<std::string, int>();
1572void MPSolver::GenerateConstraintNameIndex()
const {
1573 if (constraint_name_to_index_)
return;
1574 constraint_name_to_index_ = absl::flat_hash_map<std::string, int>();
1575 for (
const MPConstraint*
const cst : constraints_) {
1583 interface_->SetCallback(mp_callback);
1587 return interface_->SupportsCallbacks();
1593 case MPSOLVER_OPTIMAL:
1594 case MPSOLVER_FEASIBLE:
1595 case MPSOLVER_INFEASIBLE:
1596 case MPSOLVER_NOT_SOLVED:
1597 case MPSOLVER_UNBOUNDED:
1598 case MPSOLVER_ABNORMAL:
1599 case MPSOLVER_UNKNOWN_STATUS:
1603 case MPSOLVER_MODEL_IS_VALID:
1606 case MPSOLVER_MODEL_INVALID:
1607 case MPSOLVER_MODEL_INVALID_SOLUTION_HINT:
1608 case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS:
1609 case MPSOLVER_SOLVER_TYPE_UNAVAILABLE:
1613 <<
"MPSolverResponseStatusIsRpcError() called with invalid status "
1614 <<
"(value: " << status <<
")";
1626 sync_status_(MODEL_SYNCHRONIZED),
1627 result_status_(
MPSolver::NOT_SOLVED),
1629 last_constraint_index_(0),
1630 last_variable_index_(0),
1631 objective_value_(0.0),
1632 best_objective_bound_(0.0),
1638 LOG(
WARNING) <<
"Writing model not implemented in this solver interface.";
1673 solver_->variable_is_extracted_.assign(
solver_->variables_.size(),
false);
1674 solver_->constraint_is_extracted_.assign(
solver_->constraints_.size(),
false);
1680 <<
"The model has been changed since the solution was last computed."
1681 <<
" MPSolverInterface::sync_status_ = " <<
sync_status_;
1692 LOG(DFATAL) <<
"No solution exists. MPSolverInterface::result_status_ = "
1705 const double trivial_worst_bound =
1706 maximize_ ? -std::numeric_limits<double>::infinity()
1707 : std::numeric_limits<double>::infinity();
1709 LOG(DFATAL) <<
"Best objective bound only available for discrete problems.";
1710 return trivial_worst_bound;
1713 return trivial_worst_bound;
1716 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
1730 LOG(DFATAL) <<
"ComputeExactConditionNumber not implemented for "
1731 << ProtoEnumToString<MPModelRequest::SolverType>(
1732 static_cast<MPModelRequest::SolverType
>(
1767 LOG(
WARNING) <<
"Trying to set an unsupported parameter: " << param <<
".";
1771 LOG(
WARNING) <<
"Trying to set an unsupported parameter: " << param <<
".";
1775 LOG(
WARNING) <<
"Trying to set a supported parameter: " << param
1776 <<
" to an unsupported value: " <<
value;
1780 LOG(
WARNING) <<
"Trying to set a supported parameter: " << param
1781 <<
" to an unsupported value: " <<
value;
1785 return absl::UnimplementedError(
1786 absl::StrFormat(
"SetNumThreads() not supported by %s.",
SolverVersion()));
1795 LOG(
WARNING) <<
"SetSolverSpecificParametersAsString() not supported by "
1820 : relative_mip_gap_value_(kDefaultRelativeMipGap),
1822 dual_tolerance_value_(kDefaultDualTolerance),
1823 presolve_value_(kDefaultPresolve),
1824 scaling_value_(kDefaultIntegerParamValue),
1825 lp_algorithm_value_(kDefaultIntegerParamValue),
1826 incrementality_value_(kDefaultIncrementality),
1827 lp_algorithm_is_default_(true) {}
1833 relative_mip_gap_value_ =
value;
1837 primal_tolerance_value_ =
value;
1841 dual_tolerance_value_ =
value;
1845 LOG(
ERROR) <<
"Trying to set an unknown parameter: " << param <<
".";
1855 LOG(
ERROR) <<
"Trying to set a supported parameter: " << param
1856 <<
" to an unknown value: " <<
value;
1858 presolve_value_ =
value;
1863 LOG(
ERROR) <<
"Trying to set a supported parameter: " << param
1864 <<
" to an unknown value: " <<
value;
1866 scaling_value_ =
value;
1871 LOG(
ERROR) <<
"Trying to set a supported parameter: " << param
1872 <<
" to an unknown value: " <<
value;
1874 lp_algorithm_value_ =
value;
1875 lp_algorithm_is_default_ =
false;
1880 LOG(
ERROR) <<
"Trying to set a supported parameter: " << param
1881 <<
" to an unknown value: " <<
value;
1883 incrementality_value_ =
value;
1887 LOG(
ERROR) <<
"Trying to set an unknown parameter: " << param <<
".";
1908 LOG(
ERROR) <<
"Trying to reset an unknown parameter: " << param <<
".";
1925 lp_algorithm_is_default_ =
true;
1933 LOG(
ERROR) <<
"Trying to reset an unknown parameter: " << param <<
".";
1952 return relative_mip_gap_value_;
1955 return primal_tolerance_value_;
1958 return dual_tolerance_value_;
1961 LOG(
ERROR) <<
"Trying to get an unknown parameter: " << param <<
".";
1971 return presolve_value_;
1975 return lp_algorithm_value_;
1978 return incrementality_value_;
1981 return scaling_value_;
1984 LOG(
ERROR) <<
"Trying to get an unknown parameter: " << param <<
".";
#define DLOG_IF(severity, condition)
#define LOG_IF(severity, condition)
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
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:
const LinearExpr & linear_expr() const
double upper_bound() const
double lower_bound() const
The class for constraints of a Mathematical Programming (MP) model.
void SetBounds(double lb, double ub)
Sets both the lower and upper bounds.
const std::string & name() const
Returns the name of the constraint.
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.
bool indicator_value() const
const MPVariable * indicator_variable() 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).
double lb() const
Returns the lower bound.
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 OptimizationProblemType ParseSolverTypeOrDie(const std::string &solver_id)
Parses the name of the solver and returns the correct optimization type or dies.
void MakeBoolVarArray(int nb, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of boolean variables.
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.
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...
int64 nodes() const
Returns the number of branch-and-bound nodes evaluated during the solve.
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 void SolveWithProto(const MPModelRequest &model_request, MPSolutionResponse *response)
Solves the model encoded by a MPModelRequest protocol buffer and fills the solution encoded as a MPSo...
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
@ SAT_INTEGER_PROGRAMMING
@ GLPK_MIXED_INTEGER_PROGRAMMING
@ CBC_MIXED_INTEGER_PROGRAMMING
bool SetSolverSpecificParametersAsString(const std::string ¶meters)
Advanced usage: pass solver specific parameters in text format.
absl::Status SetNumThreads(int num_threads)
Sets the number of threads to use by the underlying solver.
const std::string & Name() const
Returns the name of the model set at construction.
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.
int64 iterations() const
Returns the number of simplex iterations.
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
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.
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.
const MPObjective & Objective() const
Returns the objective object.
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.
absl::Status LoadSolutionFromProto(const MPSolutionResponse &response, double tolerance=kDefaultPrimalTolerance)
Load a solution encoded in a protocol buffer onto this solver for easy access via the MPSolver interf...
MPSolverResponseStatus LoadModelFromProtoWithUniqueNamesOrDie(const MPModelProto &input_model, std::string *error_message)
Loads model from protocol buffer.
MPObjective * MutableObjective()
Returns the mutable objective object.
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.
const std::string & name() const
Returns the name of the variable.
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.
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.
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 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)
void STLDeleteElements(T *container)
std::function< int64(const Model &)> Value(IntegerVariable v)
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
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 AreWithinAbsoluteOrRelativeTolerances(FloatType x, FloatType y, FloatType relative_tolerance, FloatType absolute_tolerance)
bool SolverTypeIsMip(MPModelRequest::SolverType solver_type)
MPSolverInterface * BuildCBCInterface(MPSolver *const solver)
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)
absl::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).
MPSolverInterface * BuildSatInterface(MPSolver *const solver)
MPSolverInterface * BuildCLPInterface(MPSolver *const solver)
constexpr NamedOptimizationProblemType kOptimizationProblemTypeNames[]
MPSolverInterface * BuildGLOPInterface(MPSolver *const solver)
std::string FindErrorInMPModelProto(const MPModelProto &model, double abs_value_threshold)
Returns an empty string iff the model is valid and not trivially infeasible.
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)
bool obfuscate
Obfuscates variable and constraint names.