Google OR-Tools: ortools/linear_solver/linear_solver.cc Source File
33#include "absl/base/const_init.h"
34#include "absl/container/flat_hash_map.h"
35#include "absl/container/flat_hash_set.h"
36#include "absl/flags/flag.h"
39#include "absl/status/status.h"
40#include "absl/status/statusor.h"
41#include "absl/strings/ascii.h"
42#include "absl/strings/match.h"
43#include "absl/strings/str_cat.h"
44#include "absl/strings/str_format.h"
45#include "absl/strings/str_replace.h"
46#include "absl/strings/string_view.h"
47#include "absl/synchronization/mutex.h"
48#include "absl/synchronization/notification.h"
49#include "absl/time/clock.h"
51#include "google/protobuf/text_format.h"
68 "Systematically verify the solution when calling Solve()"
69 ", and change the return value of Solve() to ABNORMAL if"
70 " an error was detected.");
71ABSL_FLAG(bool, log_verification_errors, true,
72 "If --verify_solution is set: LOG(ERROR) all errors detected"
73 " during the verification of the solution.");
74ABSL_FLAG(bool, linear_solver_enable_verbose_output, false,
75 "If set, enables verbose output for the solver. Setting this flag"
76 " is the same as calling MPSolver::EnableOutput().");
78ABSL_FLAG(bool, mpsolver_bypass_model_validation, false,
79 "If set, the user-provided Model won't be verified before Solve()."
80 " Invalid models will typically trigger various error responses"
81 " from the underlying solvers; sometimes crashes.");
114 DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var;
120 DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var;
121 if (var == nullptr) return;
123 auto it = coefficients_.find(var);
131 if (it != coefficients_.end() && it->second != 0.0) {
132 const double old_value = it->second;
134 interface_->SetCoefficient(this, var, 0.0, old_value);
138 auto insertion_result = coefficients_.insert(std::make_pair(var, coeff));
140 insertion_result.second ? 0.0 : insertion_result.first->second;
141 insertion_result.first->second = coeff;
142 interface_->SetCoefficient(this, var, coeff, old_value);
151 const bool change = lb != lb_ || ub != ub_;
152 lb_ = lb;
153 ub_ = ub;
154 if (change && interface_->constraint_is_extracted(index_)) {
160 if (!interface_->IsContinuous()) {
161 LOG(DFATAL) << "Dual value only available for continuous problems";
164 if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0;
169 if (!interface_->IsContinuous()) {
170 LOG(DFATAL) << "Basis status only available for continuous problems";
173 if (!interface_->CheckSolutionIsSynchronizedAndExists()) {
180bool MPConstraint::ContainsNewVariables() {
182 for (const auto& entry : coefficients_) {
183 const int variable_index = entry.first->index();
184 if (variable_index >= last_variable_index ||
195 DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var;
201 DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(var)) << var;
202 if (var == nullptr) return;
204 auto it = coefficients_.find(var);
207 if (it == coefficients_.end() || it->second == 0.0) return;
210 coefficients_[var] = coeff;
221void CheckLinearExpr(const MPSolver& solver, const LinearExpr& linear_expr) {
222 for (auto var_value_pair : linear_expr.terms()) {
223 CHECK(solver.OwnsVariable(var_value_pair.first))
224 << "Bad MPVariable* in LinearExpr, did you try adding an integer to an "
232 CheckLinearExpr(*interface_->solver_, linear_expr);
233 interface_->ClearObjective();
236 for (const auto& kv : linear_expr.terms()) {
243 CheckLinearExpr(*interface_->solver_, linear_expr);
245 for (const auto& kv : linear_expr.terms()) {
288 if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0;
292 return (integer_ && interface_->IsMIP()) ? round(solution_value_)
302 if (!interface_->IsContinuous()) {
303 LOG(DFATAL) << "Reduced cost only available for continuous problems";
306 if (!interface_->CheckSolutionIsSynchronizedAndExists()) return 0.0;
311 if (!interface_->IsContinuous()) {
312 LOG(DFATAL) << "Basis status only available for continuous problems";
315 if (!interface_->CheckSolutionIsSynchronizedAndExists()) {
323 const bool change = lb != lb_ || ub != ub_;
324 lb_ = lb;
325 ub_ = ub;
326 if (change && interface_->variable_is_extracted(index_)) {
332 if (integer_ != integer) {
334 if (interface_->variable_is_extracted(index_)) {
335 interface_->SetVariableInteger(index_, integer);
341 if (priority == branching_priority_) return;
342 branching_priority_ = priority;
343 interface_->BranchingPriorityChangedForVariable(index_);
360 return absl::InvalidArgumentError("num_threads must be a positive number.");
362 const absl::Status status = interface_->SetNumThreads(num_threads);
370 const std::string& parameters) {
371 solver_specific_parameter_string_ = parameters;
372 return interface_->SetSolverSpecificParametersAsString(parameters);
379 DCHECK(solver != nullptr);
382 QCHECK(interface != nullptr)
383 << "Unsupported problem type: '" << solver->ProblemType()
384 << "'. Did you forget to link the library for this solver?";
394 return static_cast<int>(std::max(1.0L, log(1.0L * n) / log(10.0L) + 1.0));
396 return static_cast<int>(std::max(1.0, log10(static_cast<double>(n)) + 1.0));
404 problem_type_(problem_type),
405 construction_time_(absl::Now()) {
406 interface_.reset(BuildSolverInterface(this));
407 if (absl::GetFlag(FLAGS_linear_solver_enable_verbose_output)) {
410 objective_.reset(new MPObjective(interface_.get()));
425struct NamedOptimizationProblemType {
461 absl::StrReplaceAll(absl::AsciiStrToUpper(solver_id), {{"-", "_"}});
471 std::string lower_id = absl::AsciiStrToLower(id);
474 if (absl::EndsWith(lower_id, "_mip")) {
475 lower_id = lower_id.substr(0, lower_id.size() - 4);
479 if (lower_id == "cp_sat") {
485 if (named_solver.name == lower_id) {
497 if (named_solver.problem_type == optimization_problem_type) {
501 LOG(FATAL) << "Unrecognized solver type: "
508 DCHECK(solver_type != nullptr);
512 *error = absl::StrCat("Solver type: ", text, " does not exist.");
529 LOG(WARNING) << "Unrecognized solver type: " << solver_id;
533 LOG(WARNING) << "Support for " << solver_id
542 if (!variable_name_to_index_) GenerateVariableNameIndex();
544 absl::flat_hash_map<std::string, int>::const_iterator it =
545 variable_name_to_index_->find(var_name);
546 if (it == variable_name_to_index_->end()) return nullptr;
551 const std::string& constraint_name) const {
552 if (!constraint_name_to_index_) GenerateConstraintNameIndex();
554 const auto it = constraint_name_to_index_->find(constraint_name);
555 if (it == constraint_name_to_index_->end()) return nullptr;
562 const MPModelProto& input_model, std::string* error_message,
570 return LoadModelFromProtoInternal(
573 clear_names ? DEFAULT_CLEAR_NAMES
579 const MPModelProto& input_model, std::string* error_message) {
583 GenerateVariableNameIndex();
584 GenerateConstraintNameIndex();
586 return LoadModelFromProtoInternal(
593class MPVariableNamesIterator {
595 explicit MPVariableNamesIterator(const MPModelProto& model) : model_(model) {}
596 int index() const { return index_; }
597 absl::string_view name() const { return model_.variable(index_).name(); }
598 static std::string DescribeIndex(int index) {
599 return absl::StrFormat("variable[%d]", index);
601 void Advance() { ++index_; }
602 bool AtEnd() const { return index_ == model_.variable_size(); }
605 const MPModelProto& model_;
610class MPConstraintNamesIterator {
612 explicit MPConstraintNamesIterator(const MPModelProto& model)
617 index_(model_.constraint().empty() ? ~0 : 0) {}
618 int index() const { return index_; }
619 absl::string_view name() const {
620 return index_ >= 0 ? model_.constraint(index_).name()
624 : model_.general_constraint(~index_)
629 static std::string DescribeIndex(int index) {
631 ? absl::StrFormat("constraint[%d]", index)
633 "general_constraint[%d].indicator_constraint.constraint",
638 if (++index_ == model_.constraint_size()) index_ = ~0;
643 bool AtEnd() const { return ~index_ == model_.general_constraint_size(); }
646 const MPModelProto& model_;
653template <class NameIterator>
654std::string FindDuplicateNamesError(NameIterator name_iterator) {
655 absl::flat_hash_map<absl::string_view, int> name_to_index;
656 for (; !name_iterator.AtEnd(); name_iterator.Advance()) {
657 if (name_iterator.name().empty()) continue;
659 name_to_index.insert({name_iterator.name(), name_iterator.index()})
661 if (index != name_iterator.index()) {
663 "Duplicate name '%s' in %s.name() and %s.name()",
664 name_iterator.name(), NameIterator::DescribeIndex(index),
665 NameIterator::DescribeIndex(name_iterator.index()));
673 const MPModelProto& input_model, ModelProtoNamesPolicy name_policy,
674 bool check_model_validity, std::string* error_message) {
675 CHECK(error_message != nullptr);
677 if (check_model_validity) {
683 if (error.empty() && name_policy != DEFAULT_CLEAR_NAMES) {
684 error = FindDuplicateNamesError(MPVariableNamesIterator(input_model));
686 error = FindDuplicateNamesError(MPConstraintNamesIterator(input_model));
688 if (!error.empty() && name_policy == DIE_ON_DUPLICATE_NONEMPTY_NAMES) {
692 const bool clear_names = name_policy == DEFAULT_CLEAR_NAMES;
697 << "Invalid model given to LoadModelFromProto(): " << error;
698 if (absl::GetFlag(FLAGS_mpsolver_bypass_model_validation)) {
700 << "Ignoring the model error(s) because of"
701 << " --mpsolver_bypass_model_validation.";
708 if (input_model.has_quadratic_objective()) {
710 "Optimizing a quadratic objective is only supported through direct "
711 "proto solves. Please use MPSolver::SolveWithProto, or the solver's "
712 "direct proto solve function.";
719 for (int i = 0; i < input_model.variable_size(); ++i) {
720 const MPVariableProto& var_proto = input_model.variable(i);
722 MakeNumVar(var_proto.lower_bound(), var_proto.upper_bound(),
723 clear_names ? empty : var_proto.name());
724 variable->SetInteger(var_proto.is_integer());
725 if (var_proto.branching_priority() != 0) {
726 variable->SetBranchingPriority(var_proto.branching_priority());
728 objective->SetCoefficient(variable, var_proto.objective_coefficient());
731 for (const MPConstraintProto& ct_proto : input_model.constraint()) {
732 if (ct_proto.lower_bound() == -infinity() &&
733 ct_proto.upper_bound() == infinity()) {
738 MakeRowConstraint(ct_proto.lower_bound(), ct_proto.upper_bound(),
739 clear_names ? empty : ct_proto.name());
740 ct->set_is_lazy(ct_proto.is_lazy());
741 for (int j = 0; j < ct_proto.var_index_size(); ++j) {
742 ct->SetCoefficient(variables_[ct_proto.var_index(j)],
747 for (const MPGeneralConstraintProto& general_constraint :
748 input_model.general_constraint()) {
749 switch (general_constraint.general_constraint_case()) {
752 general_constraint.indicator_constraint().constraint();
753 if (proto.lower_bound() == -infinity() &&
754 proto.upper_bound() == infinity()) {
759 MPConstraint* const constraint = new MPConstraint(
760 constraint_index, proto.lower_bound(), proto.upper_bound(),
761 clear_names ? "" : proto.name(), interface_.get());
762 if (constraint_name_to_index_) {
767 constraint_is_extracted_.push_back(false);
769 constraint->set_is_lazy(proto.is_lazy());
770 for (int j = 0; j < proto.var_index_size(); ++j) {
771 constraint->SetCoefficient(variables_[proto.var_index(j)],
776 variables_[general_constraint.indicator_constraint().var_index()];
779 general_constraint.indicator_constraint().var_value();
781 if (!interface_->AddIndicatorConstraint(constraint)) {
782 *error_message = "Solver doesn't support indicator constraints";
788 *error_message = absl::StrFormat(
789 "Optimizing general constraints of type %i is only supported "
790 "through direct proto solves. Please use MPSolver::SolveWithProto, "
791 "or the solver's direct proto solve function.",
792 general_constraint.general_constraint_case());
797 objective->SetOptimizationDirection(input_model.maximize());
798 if (input_model.has_objective_offset()) {
799 objective->SetOffset(input_model.objective_offset());
804 for (int i = 0; i < input_model.solution_hint().var_index_size(); ++i) {
806 std::make_pair(variables_[input_model.solution_hint().var_index(i)],
807 input_model.solution_hint().var_value(i)));
836 CHECK(response != nullptr);
837 response->Clear();
839 ResultStatusToMPSolverResponseStatus(interface_->result_status_));
865bool InCategory(int status, int category) {
867 while (status > category) status >>= 4;
868 return status == category;
871void AppendStatusStr(absl::string_view msg, MPSolutionResponse* response) {
873 absl::StrCat(response->status_str(),
874 (response->status_str().empty() ? "" : "\n"), msg));
889 std::atomic<bool>* interrupt) {
890 CHECK(response != nullptr);
892 if (interrupt != nullptr &&
896 "Called MPSolver::SolveWithProto with an underlying solver that "
897 "doesn't support interruption.");
904 if (request->enable_internal_solver_output()) {
906 std::cout << "MPModelRequest info:\n"
912 if (solver.interface_->SupportsDirectlySolveProto(interrupt)) {
914 solver.interface_->DirectlySolveProto(std::move(request), interrupt);
919 const std::optional<LazyMutableCopy<MPModelProto>> optional_model =
921 if (!optional_model) return;
923 std::string error_message;
924 response->set_status(solver.LoadModelFromProtoInternal(
925 **optional_model, DEFAULT_CLEAR_NAMES,
931 LOG_IF(WARNING, request->enable_internal_solver_output())
932 << "LoadModelFromProtoInternal() failed even though the model was "
935 << response->status() << "); Error: " << error_message;
938 if (request->has_solver_time_limit_seconds()) {
939 solver.SetTimeLimit(absl::Seconds(request->solver_time_limit_seconds()));
941 std::string warning_message;
942 if (request->has_solver_specific_parameters()) {
944 request->solver_specific_parameters())) {
945 if (request->ignore_solver_specific_parameters_failure()) {
948 "Warning: the solver specific parameters were not successfully "
957 if (interrupt == nullptr) {
963 const absl::Time start_time = absl::Now();
964 absl::Time interrupt_time;
965 bool interrupted_by_user = false;
967 absl::Notification solve_finished;
968 auto polling_func = [&interrupt, &solve_finished, &solver,
969 &interrupted_by_user, &interrupt_time, &request]() {
970 constexpr absl::Duration kPollDelay = absl::Microseconds(100);
971 constexpr absl::Duration kMaxInterruptionDelay = absl::Seconds(10);
973 while (!interrupt->load()) {
974 if (solve_finished.HasBeenNotified()) return;
975 absl::SleepFor(kPollDelay);
981 interrupt_time = absl::Now();
982 interrupted_by_user = true;
997 for (absl::Duration poll_delay = kPollDelay;
998 absl::Now() <= interrupt_time + kMaxInterruptionDelay;
1000 if (solve_finished.WaitForNotificationWithTimeout(poll_delay)) {
1008 << "MPSolver::InterruptSolve() seems to be ignored by the "
1009 "underlying solver, despite repeated calls over at least "
1010 << absl::FormatDuration(kMaxInterruptionDelay)
1011 << ". Solver type used: "
1023 ThreadPool thread_pool(1);
1024 thread_pool.Schedule(polling_func);
1028 if (!interrupt->load()) {
1030 solver.FillSolutionResponseProto(response);
1034 "Solve not started, because the user set the atomic<bool> in "
1035 "MPSolver::SolveWithProto() to true before solving could "
1043 if (interrupted_by_user) {
1051 "User interrupted MPSolver::SolveWithProto() by setting the "
1052 "atomic<bool> to true at %s (%s after solving started.)",
1053 absl::FormatTime(interrupt_time),
1054 absl::FormatDuration(interrupt_time - start_time)),
1059 if (!warning_message.empty()) {
1065 DCHECK(output_model != nullptr);
1066 output_model->Clear();
1070 for (const MPVariable* var : variables_) {
1074 variable_proto->set_name(var->name());
1078 if (objective_->GetCoefficient(var) != 0.0) {
1080 objective_->GetCoefficient(var));
1082 if (var->branching_priority() != 0) {
1093 absl::flat_hash_map<const MPVariable*, int> var_to_index;
1094 for (int j = 0; j < static_cast<int>(variables_.size()); ++j) {
1095 var_to_index[variables_[j]] = j;
1101 if (constraint->indicator_variable() != nullptr) {
1108 constraint->indicator_variable()->index());
1110 constraint_proto = indicator_constraint_proto->mutable_constraint();
1120 std::vector<std::pair<int, double>> linear_term;
1121 for (const auto& entry : constraint->coefficients_) {
1122 const MPVariable* const var = entry.first;
1124 DCHECK_NE(-1, var_index);
1125 const double coeff = entry.second;
1126 linear_term.push_back(std::pair<int, double>(var_index, coeff));
1130 std::sort(linear_term.begin(), linear_term.end());
1132 for (const std::pair<int, double>& var_and_coeff : linear_term) {
1133 constraint_proto->add_var_index(var_and_coeff.first);
1134 constraint_proto->add_coefficient(var_and_coeff.second);
1141 if (!solution_hint_.empty()) {
1144 for (const auto& var_value_pair : solution_hint_) {
1145 hint->add_var_index(var_value_pair.first->index());
1153 interface_->result_status_ = static_cast<ResultStatus>(response.status());
1156 return absl::InvalidArgumentError(absl::StrCat(
1157 "Cannot load a solution unless its status is OPTIMAL or FEASIBLE"
1166 return absl::InvalidArgumentError(absl::StrCat(
1167 "Trying to load a solution whose number of variables (",
1169 ") does not correspond to the Solver's (", variables_.size(), ")"));
1171 interface_->ExtractModel();
1173 if (tolerance != infinity()) {
1175 double largest_error = 0;
1176 int num_vars_out_of_bounds = 0;
1177 int last_offending_var = -1;
1179 const double var_value = response.variable_value(i);
1182 const double lb_error = var->lb() - var_value;
1183 const double ub_error = var_value - var->ub();
1184 if (lb_error > tolerance || ub_error > tolerance) {
1185 ++num_vars_out_of_bounds;
1186 largest_error = std::max(largest_error, std::max(lb_error, ub_error));
1190 if (num_vars_out_of_bounds > 0) {
1191 return absl::InvalidArgumentError(absl::StrCat(
1192 "Loaded a solution whose variables matched the solver's, but ",
1193 num_vars_out_of_bounds, " of ", variables_.size(),
1194 " variables were out of their bounds, by more than the primal"
1196 tolerance, ". Max error: ", largest_error, ", last offender var is #",
1197 last_offending_var, ": '", variables_[last_offending_var]->name(),
1202 variables_[i]->set_solution_value(response.variable_value(i));
1207 return absl::InvalidArgumentError(absl::StrCat(
1208 "Trying to load a dual solution whose number of entries (",
1209 response.dual_value_size(), ") does not correspond to the Solver's (",
1210 constraints_.size(), ")"));
1213 constraints_[i]->set_dual_value(response.dual_value(i));
1219 return absl::InvalidArgumentError(absl::StrCat(
1220 "Trying to load a reduced cost solution whose number of entries (",
1222 ") does not correspond to the Solver's (", variables_.size(), ")"));
1225 variables_[i]->set_reduced_cost(response.reduced_cost(i));
1231 interface_->objective_value_ = response.objective_value();
1244 absl::MutexLock lock(global_count_mutex_);
1245 global_num_variables_ += variables_.size();
1246 global_num_constraints_ += constraints_.size();
1251 if (variable_name_to_index_) {
1252 variable_name_to_index_->clear();
1254 variable_is_extracted_.clear();
1255 if (constraint_name_to_index_) {
1256 constraint_name_to_index_->clear();
1268 const std::vector<BasisStatus>& variable_statuses,
1269 const std::vector<BasisStatus>& constraint_statuses) {
1270 interface_->SetStartingLpBasis(variable_statuses, constraint_statuses);
1276 const std::string& name) {
1279 new MPVariable(var_index, lb, ub, integer, name, interface_.get());
1280 if (variable_name_to_index_) {
1284 variable_is_extracted_.push_back(false);
1300 return MakeVar(0.0, 1.0, true, name);
1305 std::vector<MPVariable*>* vars) {
1308 const int num_digits = NumDigits(nb);
1309 for (int i = 0; i < nb; ++i) {
1311 vars->push_back(MakeVar(lb, ub, integer, name));
1314 absl::StrFormat("%s%0*d", name.c_str(), num_digits, i);
1315 vars->push_back(MakeVar(lb, ub, integer, vname));
1322 std::vector<MPVariable*>* vars) {
1323 MakeVarArray(nb, lb, ub, false, name, vars);
1346 const std::string& name) {
1349 new MPConstraint(constraint_index, lb, ub, name, interface_.get());
1350 if (constraint_name_to_index_) {
1355 constraint_is_extracted_.push_back(false);
1356 interface_->AddRowConstraint(constraint);
1369 const std::string& name) {
1370 CheckLinearExpr(*this, range.linear_expr());
1374 constraint->SetCoefficient(kv.first, kv.second);
1379int MPSolver::ComputeMaxConstraintSize(int min_constraint_index,
1380 int max_constraint_index) const {
1381 int max_constraint_size = 0;
1382 DCHECK_GE(min_constraint_index, 0);
1383 DCHECK_LE(max_constraint_index, constraints_.size());
1384 for (int i = min_constraint_index; i < max_constraint_index; ++i) {
1386 if (static_cast<int>(ct->coefficients_.size()) > max_constraint_size) {
1387 max_constraint_size = ct->coefficients_.size();
1390 return max_constraint_size;
1393bool MPSolver::HasInfeasibleConstraints() const {
1394 bool hasInfeasibleConstraints = false;
1395 for (int i = 0; i < static_cast<int>(constraints_.size()); ++i) {
1396 if (constraints_[i]->lb() > constraints_[i]->ub()) {
1397 LOG(WARNING) << "Constraint " << constraints_[i]->name() << " (" << i
1398 << ") has contradictory bounds:" << " lower bound = "
1399 << constraints_[i]->lb()
1400 << " upper bound = " << constraints_[i]->ub();
1401 hasInfeasibleConstraints = true;
1404 return hasInfeasibleConstraints;
1407bool MPSolver::HasIntegerVariables() const {
1408 for (const MPVariable* const variable : variables_) {
1409 if (variable->integer()) return true;
1416 return Solve(default_param);
1425 if (HasInfeasibleConstraints()) {
1427 return interface_->result_status_;
1431 if (absl::GetFlag(FLAGS_verify_solution)) {
1433 VLOG(1) << "--verify_solution enabled, but the solver did not find a"
1434 << " solution: skipping the verification.";
1437 absl::GetFlag(FLAGS_log_verification_errors))) {
1439 interface_->result_status_ = status;
1451std::string PrettyPrintVar(const MPVariable& var) {
1452 const std::string prefix = "Variable '" + var.name() + "': domain = ";
1459 if (var.integer() && var.ub() - var.lb() <= 1) {
1460 const int64_t lb = static_cast<int64_t>(ceil(var.lb()));
1461 const int64_t ub = static_cast<int64_t>(floor(var.ub()));
1465 return absl::StrFormat("%s{ %d }", prefix.c_str(), lb);
1467 return absl::StrFormat("%s{ %d, %d }", prefix.c_str(), lb, ub);
1471 if (var.lb() == var.ub()) {
1472 return absl::StrFormat("%s{ %f }", prefix.c_str(), var.lb());
1474 return prefix + (var.integer() ? "Integer" : "Real") + " in " +
1477 : absl::StrFormat("[%f", var.lb())) +
1480 : absl::StrFormat("%f]", var.ub()));
1483std::string PrettyPrintConstraint(const MPConstraint& constraint) {
1484 std::string prefix = "Constraint '" + constraint.name() + "': ";
1487 constraint.lb() > constraint.ub()) {
1488 return prefix + "ALWAYS FALSE";
1492 return prefix + "ALWAYS TRUE";
1494 prefix += "<linear expr>";
1496 if (constraint.lb() == constraint.ub()) {
1497 return absl::StrFormat("%s = %f", prefix.c_str(), constraint.lb());
1501 return absl::StrFormat("%s ≤ %f", prefix.c_str(), constraint.ub());
1504 return absl::StrFormat("%s ≥ %f", prefix.c_str(), constraint.lb());
1506 return absl::StrFormat("%s ∈ [%f, %f]", prefix.c_str(), constraint.lb(),
1512 interface_->ExtractModel();
1514 const double value = variable->solution_value();
1516 return absl::InvalidArgumentError(
1517 absl::StrCat("NaN value for ", PrettyPrintVar(*variable)));
1519 if (value < variable->lb()) {
1521 } else if (value > variable->ub()) {
1531 if (!interface_->CheckSolutionIsSynchronizedAndExists()) return {};
1532 std::vector<double> activities(constraints_.size(), 0.0);
1533 for (int i = 0; i < static_cast<int>(constraints_.size()); ++i) {
1536 for (const auto& entry : constraint.coefficients_) {
1537 sum.Add(entry.first->solution_value() * entry.second);
1539 activities[i] = sum.Value();
1546 double max_observed_error = 0;
1547 if (tolerance < 0) tolerance = infinity();
1557 max_observed_error = infinity();
1558 LOG_IF(ERROR, log_errors) << "NaN value for " << PrettyPrintVar(var);
1563 if (value < var.lb() - tolerance) {
1565 max_observed_error = std::max(max_observed_error, var.lb() - value);
1566 LOG_IF(ERROR, log_errors)
1567 << "Value " << value << " too low for " << PrettyPrintVar(var);
1572 if (value > var.ub() + tolerance) {
1574 max_observed_error = std::max(max_observed_error, value - var.ub());
1575 LOG_IF(ERROR, log_errors)
1576 << "Value " << value << " too high for " << PrettyPrintVar(var);
1581 if (fabs(value - round(value)) > tolerance) {
1584 std::max(max_observed_error, fabs(value - round(value)));
1585 LOG_IF(ERROR, log_errors)
1586 << "Non-integer value " << value << " for " << PrettyPrintVar(var);
1590 if (!IsMIP() && HasIntegerVariables()) {
1591 LOG_IF(INFO, log_errors) << "Skipped variable integrality check, because "
1592 << "a continuous relaxation of the model was "
1593 << "solved (i.e., the selected solver does not "
1594 << "support integer variables).";
1599 for (int i = 0; i < static_cast<int>(constraints_.size()); ++i) {
1601 const double activity = activities[i];
1603 double inaccurate_activity = 0.0;
1604 for (const auto& entry : constraint.coefficients_) {
1605 inaccurate_activity += entry.first->solution_value() * entry.second;
1608 if (std::isnan(activity) || std::isnan(inaccurate_activity)) {
1610 max_observed_error = infinity();
1611 LOG_IF(ERROR, log_errors)
1612 << "NaN value for " << PrettyPrintConstraint(constraint);
1616 if (constraint.indicator_variable() == nullptr ||
1617 std::round(constraint.indicator_variable()->solution_value()) ==
1620 if (activity < constraint.lb() - tolerance) {
1623 std::max(max_observed_error, constraint.lb() - activity);
1624 LOG_IF(ERROR, log_errors)
1625 << "Activity " << activity << " too low for "
1626 << PrettyPrintConstraint(constraint);
1627 } else if (inaccurate_activity < constraint.lb() - tolerance) {
1628 LOG_IF(WARNING, log_errors)
1629 << "Activity " << activity << ", computed with the (inaccurate)"
1630 << " standard sum of its terms, is too low for "
1631 << PrettyPrintConstraint(constraint);
1635 if (activity > constraint.ub() + tolerance) {
1638 std::max(max_observed_error, activity - constraint.ub());
1639 LOG_IF(ERROR, log_errors)
1640 << "Activity " << activity << " too high for "
1641 << PrettyPrintConstraint(constraint);
1642 } else if (inaccurate_activity > constraint.ub() + tolerance) {
1643 LOG_IF(WARNING, log_errors)
1644 << "Activity " << activity << ", computed with the (inaccurate)"
1645 << " standard sum of its terms, is too high for "
1646 << PrettyPrintConstraint(constraint);
1655 objective_sum.Add(objective.offset());
1656 double inaccurate_objective_value = objective.offset();
1657 for (const auto& entry : objective.coefficients_) {
1658 const double term = entry.first->solution_value() * entry.second;
1659 objective_sum.Add(term);
1660 inaccurate_objective_value += term;
1662 const double actual_objective_value = objective_sum.Value();
1664 objective.Value(), actual_objective_value, tolerance, tolerance)) {
1666 max_observed_error = std::max(
1667 max_observed_error, fabs(actual_objective_value - objective.Value()));
1668 LOG_IF(ERROR, log_errors)
1669 << "Objective value " << objective.Value() << " isn't accurate"
1670 << ", it should be " << actual_objective_value
1671 << " (delta=" << actual_objective_value - objective.Value() << ").";
1673 inaccurate_objective_value,
1675 LOG_IF(WARNING, log_errors)
1676 << "Objective value " << objective.Value() << " doesn't correspond"
1677 << " to the value computed with the standard (and therefore inaccurate)"
1681 LOG_IF(ERROR, log_errors)
1682 << "There were " << num_errors << " errors above the tolerance ("
1683 << tolerance << "), the largest was " << max_observed_error;
1704 if (var == nullptr) return false;
1705 if (var->index() >= 0 && var->index() < static_cast<int>(variables_.size())) {
1707 return variables_[var->index()] == var;
1737 for (const auto& var_value_pair : hint) {
1739 << "hint variable does not belong to this solver";
1744void MPSolver::GenerateVariableNameIndex() const {
1745 if (variable_name_to_index_) return;
1746 variable_name_to_index_ = absl::flat_hash_map<std::string, int>();
1747 for (const MPVariable* const var : variables_) {
1752void MPSolver::GenerateConstraintNameIndex() const {
1753 if (constraint_name_to_index_) return;
1754 constraint_name_to_index_ = absl::flat_hash_map<std::string, int>();
1755 for (const MPConstraint* const cst : constraints_) {
1756 gtl::InsertOrDie(&*constraint_name_to_index_, cst->name(), cst->index());
1771absl::Mutex MPSolver::global_count_mutex_(absl::kConstInit);
1772int64_t MPSolver::global_num_variables_ = 0;
1773int64_t MPSolver::global_num_constraints_ = 0;
1812 << "MPSolverResponseStatusIsRpcError() called with invalid status "
1872 solver_->variable_is_extracted_.assign(solver_->variables_.size(), false);
1873 solver_->constraint_is_extracted_.assign(solver_->constraints_.size(), false);
1879 << "The model has been changed since the solution was last computed."
1880 << " MPSolverInterface::sync_status_ = " << sync_status_;
1904 const double trivial_worst_bound =
1905 maximize_ ? -std::numeric_limits<double>::infinity()
1906 : std::numeric_limits<double>::infinity();
1908 VLOG(1) << "Best objective bound only available for discrete problems.";
1909 return trivial_worst_bound;
1912 return trivial_worst_bound;
1915 if (solver_->variables_.empty() && solver_->constraints_.empty()) {
1916 return solver_->Objective().offset();
1929 LOG(DFATAL) << "ComputeExactConditionNumber not implemented for "
1932 solver_->ProblemType()));
1974 LOG(WARNING) << "Trying to set a supported parameter: " << param
1979 LOG(WARNING) << "Trying to set a supported parameter: " << param
1984 return absl::UnimplementedError(
1985 absl::StrFormat("SetNumThreads() not supported by %s.", SolverVersion()));
1989 const std::string& parameters) {
1990 if (parameters.empty()) {
1994 LOG(WARNING) << "SetSolverSpecificParametersAsString() not supported by "
2032 relative_mip_gap_value_ = value;
2036 primal_tolerance_value_ = value;
2040 dual_tolerance_value_ = value;
2044 LOG(ERROR) << "Trying to set an unknown parameter: " << param << ".";
2054 LOG(ERROR) << "Trying to set a supported parameter: " << param
2055 << " to an unknown value: " << value;
2062 LOG(ERROR) << "Trying to set a supported parameter: " << param
2063 << " to an unknown value: " << value;
2070 LOG(ERROR) << "Trying to set a supported parameter: " << param
2071 << " to an unknown value: " << value;
2073 lp_algorithm_value_ = value;
2074 lp_algorithm_is_default_ = false;
2079 LOG(ERROR) << "Trying to set a supported parameter: " << param
2080 << " to an unknown value: " << value;
2082 incrementality_value_ = value;
2086 LOG(ERROR) << "Trying to set an unknown parameter: " << param << ".";
2124 lp_algorithm_is_default_ = true;
2132 LOG(ERROR) << "Trying to reset an unknown parameter: " << param << ".";
2151 return relative_mip_gap_value_;
2154 return primal_tolerance_value_;
2157 return dual_tolerance_value_;
2160 LOG(ERROR) << "Trying to get an unknown parameter: " << param << ".";
2174 return lp_algorithm_value_;
2177 return incrementality_value_;
2183 LOG(ERROR) << "Trying to get an unknown parameter: " << param << ".";
2193#if !defined(__PORTABLE_PLATFORM__)
2195 abbreviated_request = request;
2198 google::protobuf::TextFormat::PrintToString(abbreviated_request, &out);
2200 out = "<Info unavailable because: __PORTABLE_PLATFORM__>\n";
2203 absl::StrAppendFormat(&out, "model_name: '%s'\n", request.model().name());
2217MPSolverInterfaceFactoryRepository::~MPSolverInterfaceFactoryRepository() {
2218 absl::MutexLock lock(mutex_);
2226 std::function<bool()> is_runtime_ready) {
2227 absl::MutexLock lock(mutex_);
2228 if (!is_runtime_ready) is_runtime_ready = []() { return true; };
2229 map_[problem_type] = Entry{
2230 .factory = std::move(factory),
2243 absl::MutexLock lock(mutex_);
2245 CHECK(entry != nullptr) << "No factory registered for problem type "
2247 CHECK(entry->is_runtime_ready())
2255 const Entry* entry = gtl::FindOrNull(map_, problem_type);
2256 if (entry == nullptr) return false;
2260std::vector<MPSolver::OptimizationProblemType>
2262 std::vector<MPSolver::OptimizationProblemType> out;
2263 for (auto it = map_.begin(); it != map_.end(); ++it) {
2269std::string MPSolverInterfaceFactoryRepository
void Add(const FpNumber &value)
const absl::flat_hash_map< const MPVariable *, double > & terms() const
double upper_bound() const
const LinearExpr & linear_expr() const
double lower_bound() const
void set_name(Arg_ &&arg, Args_... args)
void set_lower_bound(double value)
void set_is_lazy(bool value)
void add_coefficient(double value)
void set_upper_bound(double value)
void add_var_index(::int32_t value)
void Clear()
Clears all variables and coefficients. Does not clear the bounds.
Definition linear_solver.cc:145
void SetCoefficient(const MPVariable *var, double coeff)
Definition linear_solver.cc:119
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
MPSolver::BasisStatus basis_status() const
Definition linear_solver.cc:168
double GetCoefficient(const MPVariable *var) const
Definition linear_solver.cc:113
void SetBounds(double lb, double ub)
Sets both the lower and upper bounds.
Definition linear_solver.cc:150
double dual_value() const
Definition linear_solver.cc:159
::operations_research::MPIndicatorConstraint *PROTOBUF_NONNULL mutable_indicator_constraint()
void set_name(Arg_ &&arg, Args_... args)
void set_var_index(::int32_t value)
void set_var_value(::int32_t value)
::operations_research::MPConstraintProto *PROTOBUF_NONNULL mutable_constraint()
void set_maximize(bool value)
::operations_research::MPConstraintProto *PROTOBUF_NONNULL add_constraint()
::operations_research::MPVariableProto *PROTOBUF_NONNULL add_variable()
::operations_research::MPGeneralConstraintProto *PROTOBUF_NONNULL add_general_constraint()
::operations_research::PartialVariableAssignment *PROTOBUF_NONNULL mutable_solution_hint()
void set_objective_offset(double value)
ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL
void set_name(Arg_ &&arg, Args_... args)
const ::std::string & name() const
static constexpr SolverType CPLEX_LINEAR_PROGRAMMING
static constexpr SolverType CBC_MIXED_INTEGER_PROGRAMMING
MPModelRequest_SolverType SolverType
static constexpr SolverType CLP_LINEAR_PROGRAMMING
static constexpr SolverType HIGHS_LINEAR_PROGRAMMING
static constexpr SolverType SAT_INTEGER_PROGRAMMING
static constexpr SolverType HIGHS_MIXED_INTEGER_PROGRAMMING
static constexpr SolverType BOP_INTEGER_PROGRAMMING
static constexpr SolverType GUROBI_MIXED_INTEGER_PROGRAMMING
static constexpr SolverType PDLP_LINEAR_PROGRAMMING
static constexpr SolverType XPRESS_LINEAR_PROGRAMMING
static constexpr SolverType KNAPSACK_MIXED_INTEGER_PROGRAMMING
static constexpr SolverType GLPK_MIXED_INTEGER_PROGRAMMING
static bool SolverType_Parse(::absl::string_view name, SolverType *PROTOBUF_NONNULL value)
static constexpr SolverType GLPK_LINEAR_PROGRAMMING
static constexpr SolverType GUROBI_LINEAR_PROGRAMMING
static constexpr SolverType CPLEX_MIXED_INTEGER_PROGRAMMING
const ::operations_research::MPModelProto & model() const
static constexpr SolverType GLOP_LINEAR_PROGRAMMING
static constexpr SolverType SCIP_MIXED_INTEGER_PROGRAMMING
static constexpr SolverType XPRESS_MIXED_INTEGER_PROGRAMMING
A class to express a linear objective.
double BestBound() const
Definition linear_solver.cc:279
void SetCoefficient(const MPVariable *var, double coeff)
Definition linear_solver.cc:200
void Clear()
Definition linear_solver.cc:250
double GetCoefficient(const MPVariable *var) const
Definition linear_solver.cc:194
double Value() const
Definition linear_solver.cc:272
bool minimization() const
Is the optimization direction set to minimize?
Definition linear_solver.cc:270
bool maximization() const
Is the optimization direction set to maximize?
Definition linear_solver.cc:268
double offset() const
Gets the constant term in the objective.
void AddLinearExpr(const LinearExpr &linear_expr)
Adds linear_expr to the current objective, does not change the direction.
Definition linear_solver.cc:242
void OptimizeLinearExpr(const LinearExpr &linear_expr, bool is_maximization)
Definition linear_solver.cc:230
void SetOptimizationDirection(bool maximize)
Sets the optimization direction (maximize: true or minimize: false).
Definition linear_solver.cc:257
void SetMinimization()
Sets the optimization direction to minimize.
void add_variable_value(double value)
::operations_research::MPSolveInfo *PROTOBUF_NONNULL mutable_solve_info()
bool has_best_objective_bound() const
double dual_value(int index) const
::operations_research::MPSolverResponseStatus status() const
double best_objective_bound() const
int reduced_cost_size() const
void add_reduced_cost(double value)
void set_objective_value(double value)
double variable_value(int index) const
bool has_objective_value() const
void set_best_objective_bound(double value)
double reduced_cost(int index) const
void set_status_str(Arg_ &&arg, Args_... args)
double objective_value() const
ABSL_ATTRIBUTE_REINITIALIZES void Clear() PROTOBUF_FINAL
void add_dual_value(double value)
int dual_value_size() const
void set_status(::operations_research::MPSolverResponseStatus value)
int variable_value_size() const
void set_solve_wall_time_seconds(double value)
std::string PrettyPrintAllRegisteredProblemTypes() const
Definition linear_solver.cc:2270
MPSolverInterface * Create(MPSolver *solver) const
Definition linear_solver.cc:2241
std::vector< MPSolver::OptimizationProblemType > ListAllRegisteredProblemTypes() const
Definition linear_solver.cc:2261
static MPSolverInterfaceFactoryRepository * GetInstance()
Definition linear_solver.cc:2209
bool Unregister(MPSolver::OptimizationProblemType problem_type)
Definition linear_solver.cc:2235
bool Supports(MPSolver::OptimizationProblemType problem_type) const
Definition linear_solver.cc:2253
void Register(MPSolverInterfaceFactory factory, MPSolver::OptimizationProblemType problem_type, std::function< bool()> is_runtime_ready={})
Definition linear_solver.cc:2223
double best_objective_bound() const
Definition linear_solver.cc:1903
bool CheckSolutionIsSynchronized() const
Definition linear_solver.cc:1876
virtual void SetPrimalTolerance(double value)=0
virtual void ExtractNewConstraints()=0
virtual void ExtractObjective()=0
void InvalidateSolutionSynchronization()
Definition linear_solver.cc:1921
virtual void SetRelativeMipGap(double value)=0
virtual bool IsMIP() const =0
void ResetExtractionInformation()
Definition linear_solver.cc:1868
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
Definition linear_solver.cc:1977
int last_variable_index() const
virtual void SetPresolveMode(int value)=0
int last_constraint_index_
virtual std::string SolverVersion() const =0
virtual absl::Status SetNumThreads(int num_threads)
Definition linear_solver.cc:1983
virtual bool SetSolverSpecificParametersAsString(const std::string ¶meters)
Definition linear_solver.cc:1988
static const int kDummyVariableIndex
virtual bool CheckSolutionExists() const
Definition linear_solver.cc:1888
virtual void SetLpAlgorithm(int value)=0
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
Definition linear_solver.cc:1968
bool variable_is_extracted(int var_index) const
void SetUnsupportedDoubleParam(MPSolverParameters::DoubleParam param)
Definition linear_solver.cc:1964
virtual void ExtractNewVariables()=0
double objective_value() const
Definition linear_solver.cc:1898
void ExtractModel()
Definition linear_solver.cc:1840
double best_objective_bound_
void SetDoubleParamToUnsupportedValue(MPSolverParameters::DoubleParam param, double value)
Definition linear_solver.cc:1972
virtual double ComputeExactConditionNumber() const
Definition linear_solver.cc:1927
virtual void Write(const std::string &filename)
Definition linear_solver.cc:1836
void SetMIPParameters(const MPSolverParameters ¶m)
Definition linear_solver.cc:1957
virtual ~MPSolverInterface()
Definition linear_solver.cc:1834
virtual void SetDualTolerance(double value)=0
MPSolverInterface(MPSolver *solver)
Definition linear_solver.cc:1823
void SetCommonParameters(const MPSolverParameters ¶m)
Definition linear_solver.cc:1936
bool CheckSolutionIsSynchronizedAndExists() const
MPSolver::ResultStatus result_status_
SynchronizationStatus sync_status_
static const PresolveValues kDefaultPresolve
void ResetIntegerParam(MPSolverParameters::IntegerParam param)
Definition linear_solver.cc:2112
static const double kDefaultDualTolerance
static const double kDefaultPrimalTolerance
DoubleParam
Enumeration of parameters that take continuous values.
@ DUAL_TOLERANCE
Advanced usage: tolerance for dual feasibility of basic solutions.
@ RELATIVE_MIP_GAP
Limit for relative MIP gap.
double GetDoubleParam(MPSolverParameters::DoubleParam param) const
Returns the value of a double parameter.
Definition linear_solver.cc:2147
PresolveValues
For each categorical parameter, enumeration of possible values.
@ PRESOLVE_OFF
Presolve is off.
@ PRESOLVE_ON
Presolve is on.
static const double kUnknownDoubleParamValue
static const int kUnknownIntegerParamValue
void ResetDoubleParam(MPSolverParameters::DoubleParam param)
Definition linear_solver.cc:2091
static const int kDefaultIntegerParamValue
@ BARRIER
Barrier algorithm.
void SetDoubleParam(MPSolverParameters::DoubleParam param, double value)
Sets a double parameter to a specific value.
Definition linear_solver.cc:2028
IntegerParam
Enumeration of parameters that take integer or categorical values.
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
@ PRESOLVE
Advanced usage: presolve mode.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
MPSolverParameters()
The constructor sets all parameters to their default value.
Definition linear_solver.cc:2018
static const IncrementalityValues kDefaultIncrementality
IncrementalityValues
Advanced usage: Incrementality options.
@ INCREMENTALITY_OFF
Start solve from scratch.
static const double kDefaultRelativeMipGap
@ SCALING_ON
Scaling is on.
@ SCALING_OFF
Scaling is off.
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
Definition linear_solver.cc:2166
static const double kDefaultDoubleParamValue
void SetIntegerParam(MPSolverParameters::IntegerParam param, int value)
Sets a integer parameter to a specific value.
Definition linear_solver.cc:2049
static void SolveLazyMutableRequest(LazyMutableCopy< MPModelRequest > request, MPSolutionResponse *response, std::atomic< bool > *interrupt=nullptr)
Definition linear_solver.cc:887
int NumVariables() const
Returns the number of variables.
void Reset()
Definition linear_solver.cc:1263
static MPSolver * CreateSolver(const std::string &solver_id)
Definition linear_solver.cc:526
void SetStartingLpBasis(const std::vector< MPSolver::BasisStatus > &variable_statuses, const std::vector< MPSolver::BasisStatus > &constraint_statuses)
Definition linear_solver.cc:1267
MPVariable * MakeVar(double lb, double ub, bool integer, const std::string &name)
Definition linear_solver.cc:1275
MPVariable * MakeIntVar(double lb, double ub, const std::string &name)
Creates an integer variable.
Definition linear_solver.cc:1294
int NumConstraints() const
Returns the number of constraints.
@ MODEL_INVALID
the model is trivially invalid (NaN coefficients, etc).
@ 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.
ResultStatus Solve()
Solves the problem using the default parameter values.
Definition linear_solver.cc:1414
MPSolverResponseStatus LoadModelFromProto(const MPModelProto &input_model, std::string *error_message, bool clear_names=true)
Definition linear_solver.cc:561
bool IsMIP() const
Definition linear_solver.cc:348
bool VerifySolution(double tolerance, bool log_errors) const
Definition linear_solver.cc:1545
void MakeVarArray(int nb, double lb, double ub, bool integer, const std::string &name_prefix, std::vector< MPVariable * > *vars)
Definition linear_solver.cc:1303
int64_t nodes() const
Definition linear_solver.cc:1697
bool ExportModelAsLpFormat(bool obfuscate, std::string *model_str) const
Definition linear_solver.cc:1712
const MPObjective & Objective() const
void SetCallback(MPCallback *mp_callback)
Definition linear_solver.cc:1762
@ GLPK_MIXED_INTEGER_PROGRAMMING
@ GLOP_LINEAR_PROGRAMMING
@ SCIP_MIXED_INTEGER_PROGRAMMING
@ CPLEX_LINEAR_PROGRAMMING
@ SAT_INTEGER_PROGRAMMING
@ XPRESS_MIXED_INTEGER_PROGRAMMING
@ CBC_MIXED_INTEGER_PROGRAMMING
@ HIGHS_MIXED_INTEGER_PROGRAMMING
@ GUROBI_MIXED_INTEGER_PROGRAMMING
@ XPRESS_LINEAR_PROGRAMMING
@ PDLP_LINEAR_PROGRAMMING
@ HIGHS_LINEAR_PROGRAMMING
@ BOP_INTEGER_PROGRAMMING
@ GLPK_LINEAR_PROGRAMMING
@ CPLEX_MIXED_INTEGER_PROGRAMMING
@ KNAPSACK_MIXED_INTEGER_PROGRAMMING
@ GUROBI_LINEAR_PROGRAMMING
bool InterruptSolve()
Definition linear_solver.cc:1265
void SetTimeLimit(absl::Duration time_limit)
void Clear()
Definition linear_solver.cc:1242
MPSolverResponseStatus LoadModelFromProtoWithUniqueNamesOrDie(const MPModelProto &input_model, std::string *error_message)
Definition linear_solver.cc:578
bool SetSolverSpecificParametersAsString(const std::string ¶meters)
Definition linear_solver.cc:369
MPVariable * MakeBoolVar(const std::string &name)
Creates a boolean variable.
Definition linear_solver.cc:1299
virtual OptimizationProblemType ProblemType() const
Returns the optimization problem type set at construction.
ABSL_MUST_USE_RESULT bool NextSolution()
Definition linear_solver.cc:1760
static bool SupportsProblemType(OptimizationProblemType problem_type)
Definition linear_solver.cc:416
void MakeIntVarArray(int nb, double lb, double ub, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of integer variables.
Definition linear_solver.cc:1326
double ComputeExactConditionNumber() const
Definition linear_solver.cc:1699
absl::Status SetNumThreads(int num_threads)
Definition linear_solver.cc:358
MPVariable * variable(int index) const
absl::Status ClampSolutionWithinBounds()
Definition linear_solver.cc:1511
bool OwnsVariable(const MPVariable *var) const
Definition linear_solver.cc:1703
void MakeNumVarArray(int nb, double lb, double ub, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of continuous variables.
Definition linear_solver.cc:1320
virtual ~MPSolver()
Definition linear_solver.cc:413
double solver_infinity()
Definition linear_solver.cc:1273
std::vector< double > ComputeConstraintActivities() const
Definition linear_solver.cc:1529
bool SupportsCallbacks() const
Definition linear_solver.cc:1766
void FillSolutionResponseProto(MPSolutionResponse *response) const
Encodes the current solution in a solution response protocol buffer.
Definition linear_solver.cc:835
int64_t wall_time() const
void ExportModelToProto(MPModelProto *output_model) const
Exports model to protocol buffer.
Definition linear_solver.cc:1064
static std::string GetMPModelRequestLoggingInfo(const MPModelRequest &request)
Definition linear_solver.cc:2190
MPConstraint * MakeRowConstraint()
Creates a constraint with -infinity and +infinity bounds.
Definition linear_solver.cc:1341
MPObjective * MutableObjective()
Returns the mutable objective object.
bool OutputIsEnabled() const
Definition linear_solver.cc:1689
static OptimizationProblemType ParseSolverTypeOrDie(const std::string &solver_id)
Definition linear_solver.cc:518
absl::Status LoadSolutionFromProto(const MPSolutionResponse &response, double tolerance=std::numeric_limits< double >::infinity())
Definition linear_solver.cc:1151
MPVariable * MakeNumVar(double lb, double ub, const std::string &name)
Creates a continuous variable.
Definition linear_solver.cc:1289
MPSolver(const std::string &name, OptimizationProblemType problem_type)
Create a solver with the given name and underlying solver backend.
Definition linear_solver.cc:401
MPConstraint * LookupConstraintOrNull(const std::string &constraint_name) const
Definition linear_solver.cc:550
MPConstraint * constraint(int index) const
static int64_t global_num_variables()
Definition linear_solver.cc:1776
void SetHint(std::vector< std::pair< const MPVariable *, double > > hint)
Definition linear_solver.cc:1736
void * underlying_solver()
Definition linear_solver.cc:354
MPVariable * LookupVariableOrNull(const std::string &var_name) const
Definition linear_solver.cc:541
void Write(const std::string &file_name)
Definition linear_solver.cc:1446
static int64_t global_num_constraints()
Definition linear_solver.cc:1782
const std::string & Name() const
Returns the name of the model set at construction.
bool ExportModelAsMpsFormat(bool fixed_format, bool obfuscate, std::string *model_str) const
Definition linear_solver.cc:1724
static bool ParseSolverType(absl::string_view solver_id, OptimizationProblemType *type)
Definition linear_solver.cc:457
static void SolveWithProto(const MPModelRequest &model_request, MPSolutionResponse *response, std::atomic< bool > *interrupt=nullptr)
Definition linear_solver.cc:880
std::string SolverVersion() const
Returns a string describing the underlying solver and its version.
Definition linear_solver.cc:350
void MakeBoolVarArray(int nb, const std::string &name, std::vector< MPVariable * > *vars)
Creates an array of boolean variables.
Definition linear_solver.cc:1332
void set_upper_bound(double value)
void set_name(Arg_ &&arg, Args_... args)
void set_is_integer(bool value)
void set_objective_coefficient(double value)
void set_branching_priority(::int32_t value)
void set_lower_bound(double value)
The class for variables of a Mathematical Programming (MP) model.
double reduced_cost() const
Definition linear_solver.cc:301
void SetInteger(bool integer)
Sets the integrality requirement of the variable.
Definition linear_solver.cc:331
bool integer() const
Returns the integrality requirement of the variable.
void SetBranchingPriority(int priority)
Definition linear_solver.cc:340
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
void SetBounds(double lb, double ub)
Sets both the lower and upper bounds.
Definition linear_solver.cc:322
const std::string & name() const
Returns the name of the variable.
double solution_value() const
Definition linear_solver.cc:287
MPSolver::BasisStatus basis_status() const
Definition linear_solver.cc:310
int index() const
Returns the index of the variable in the MPSolver::variables_.
double unrounded_solution_value() const
Definition linear_solver.cc:296
void add_var_index(::int32_t value)
void add_var_value(double value)
void Schedule(absl::AnyInvocable< void() && > callback)
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.")
void STLDeleteElements(T *container)
void InsertOrDie(Collection *const collection, const typename Collection::value_type &value)
const Collection::value_type::second_type * FindOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
const ::std::string & MPModelRequest_SolverType_Name(T value)
constexpr double kDefaultPrimalTolerance
std::function< MPSolverInterface *(MPSolver *)> MPSolverInterfaceFactory
bool AreWithinAbsoluteOrRelativeTolerances(FloatType x, FloatType y, FloatType relative_tolerance, FloatType absolute_tolerance)
absl::StatusOr< std::string > ExportModelAsLpFormat(const MPModelProto &model, const MPModelExportOptions &options)
bool SolverTypeSupportsInterruption(const MPModelRequest::SolverType solver)
bool MPSolverResponseStatusIsRpcError(MPSolverResponseStatus status)
Definition linear_solver.cc:1787
bool SolverTypeIsMip(MPModelRequest::SolverType solver_type)
Definition linear_solver.cc:85
std::string ProtoEnumToString(ProtoEnumType enum_value)
constexpr NamedOptimizationProblemType kOptimizationProblemTypeNames[]
Definition linear_solver.cc:436
@ MPSOLVER_CANCELLED_BY_USER
@ MPSOLVER_MODEL_INVALID_SOLUTION_HINT
@ MPSOLVER_UNKNOWN_STATUS
@ MPSOLVER_MODEL_IS_VALID
@ MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS
@ MPSOLVER_INCOMPATIBLE_OPTIONS
@ MPSOLVER_SOLVER_TYPE_UNAVAILABLE
std::optional< LazyMutableCopy< MPModelProto > > GetMPModelOrPopulateResponse(LazyMutableCopy< MPModelRequest > &request, MPSolutionResponse *response)
std::string FindErrorInMPModelProto(const MPModelProto &model, double abs_value_threshold, const bool accept_trivially_infeasible_bounds)
bool AbslParseFlag(const absl::string_view text, MPSolver::OptimizationProblemType *solver_type, std::string *error)
Definition linear_solver.cc:505
absl::StatusOr< std::string > ExportModelAsMpsFormat(const MPModelProto &model, const MPModelExportOptions &options)
absl::string_view ToString(MPSolver::OptimizationProblemType optimization_problem_type)
Definition linear_solver.cc:494
bool obfuscate
Obfuscates variable and constraint names.