26#include "absl/log/check.h"
27#include "absl/log/log.h"
28#include "absl/strings/match.h"
29#include "absl/strings/str_cat.h"
30#include "absl/strings/str_join.h"
35#include "ortools/linear_solver/linear_solver.pb.h"
62 model_ = other_helper.
model();
87 MPModelRequest request;
90 model_ = request.model();
97 if (absl::EndsWith(filename,
"txt")) {
107 absl::StatusOr<MPModelProto> model_or =
109 if (!model_or.ok())
return false;
110 model_ = model_or.value();
115 absl::StatusOr<MPModelProto> model_or =
117 if (!model_or.ok())
return false;
118 model_ = model_or.value();
124 if (!model_or.ok())
return false;
125 model_ = model_or.value();
135 if (!model_or.ok())
return false;
136 model_ = model_or.value();
145 const int index = model_.variable_size();
146 model_.add_variable();
151 model_.mutable_variable(var_index)->set_lower_bound(lb);
155 model_.mutable_variable(var_index)->set_upper_bound(ub);
159 model_.mutable_variable(var_index)->set_is_integer(is_integer);
164 model_.mutable_variable(var_index)->set_objective_coefficient(coeff);
168 model_.mutable_variable(var_index)->set_name(
name);
172 return model_.variable(var_index).lower_bound();
176 return model_.variable(var_index).upper_bound();
180 return model_.variable(var_index).is_integer();
184 return model_.variable(var_index).objective_coefficient();
188 return model_.variable(var_index).name();
192 const int index = model_.constraint_size();
193 model_.add_constraint();
198 model_.mutable_constraint(ct_index)->set_lower_bound(lb);
202 model_.mutable_constraint(ct_index)->set_upper_bound(ub);
206 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
207 ct_proto->clear_var_index();
208 ct_proto->clear_coefficient();
213 if (coeff == 0.0)
return;
214 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
215 ct_proto->add_var_index(var_index);
216 ct_proto->add_coefficient(coeff);
221 if (coeff == 0.0)
return;
222 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
223 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
224 if (ct_proto->var_index(i) == var_index) {
225 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
231 ct_proto->add_var_index(var_index);
232 ct_proto->add_coefficient(coeff);
236 const std::string&
name) {
237 model_.mutable_constraint(ct_index)->set_name(
name);
242 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
243 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
244 if (ct_proto->var_index(i) == var_index) {
245 ct_proto->set_coefficient(i, coeff);
251 ct_proto->add_var_index(var_index);
252 ct_proto->add_coefficient(coeff);
256 return model_.constraint(ct_index).lower_bound();
260 return model_.constraint(ct_index).upper_bound();
264 return model_.constraint(ct_index).name();
268 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
269 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
273 int ct_index)
const {
274 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
275 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
279 const int index = model_.general_constraint_size();
281 model_.add_general_constraint()->mutable_indicator_constraint();
286 const MPGeneralConstraintProto& gen = model_.general_constraint(ct_index);
287 return gen.general_constraint_case() ==
288 MPGeneralConstraintProto::kIndicatorConstraint;
294 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
295 MPConstraintProto* ct_proto =
296 gen->mutable_indicator_constraint()->mutable_constraint();
297 ct_proto->set_lower_bound(lb);
303 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
304 MPConstraintProto* ct_proto =
305 gen->mutable_indicator_constraint()->mutable_constraint();
306 ct_proto->set_upper_bound(ub);
310 MPConstraintProto* ct_proto = model_.mutable_general_constraint(ct_index)
311 ->mutable_indicator_constraint()
312 ->mutable_constraint();
313 ct_proto->clear_var_index();
314 ct_proto->clear_coefficient();
320 if (coeff == 0.0)
return;
321 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
322 MPConstraintProto* ct_proto =
323 gen->mutable_indicator_constraint()->mutable_constraint();
324 ct_proto->add_var_index(var_index);
325 ct_proto->add_coefficient(coeff);
332 if (coeff == 0.0)
return;
333 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
334 MPConstraintProto* ct_proto =
335 gen->mutable_indicator_constraint()->mutable_constraint();
336 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
337 if (ct_proto->var_index(i) == var_index) {
338 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
344 ct_proto->add_var_index(var_index);
345 ct_proto->add_coefficient(coeff);
349 const std::string&
name) {
350 model_.mutable_general_constraint(ct_index)->set_name(
name);
357 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
358 MPConstraintProto* ct_proto =
359 gen->mutable_indicator_constraint()->mutable_constraint();
360 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
361 if (ct_proto->var_index(i) == var_index) {
362 ct_proto->set_coefficient(i, coeff);
368 ct_proto->add_var_index(var_index);
369 ct_proto->add_coefficient(coeff);
375 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
376 gen->mutable_indicator_constraint()->set_var_index(var_index);
382 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
383 gen->mutable_indicator_constraint()->set_var_value(positive);
388 return model_.general_constraint(ct_index)
389 .indicator_constraint()
396 return model_.general_constraint(ct_index)
397 .indicator_constraint()
404 return model_.general_constraint(ct_index).name();
408 int ct_index)
const {
410 const MPConstraintProto& ct_proto =
411 model_.general_constraint(ct_index).indicator_constraint().constraint();
412 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
416 int ct_index)
const {
418 const MPConstraintProto& ct_proto =
419 model_.general_constraint(ct_index).indicator_constraint().constraint();
420 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
425 return model_.general_constraint(ct_index).indicator_constraint().var_index();
430 return model_.general_constraint(ct_index)
431 .indicator_constraint()
438 return model_.constraint_size() + model_.general_constraint_size();
444 model_.set_name(
name);
447 for (MPVariableProto& var : *model_.mutable_variable()) {
448 var.clear_objective_coefficient();
459 return model_.objective_offset();
463 model_.set_objective_offset(offset);
469 model_.mutable_solution_hint()->add_var_index(var_index);
470 model_.mutable_solution_hint()->add_var_value(var_value);
474 const MPModelRequest& request) {
477 request.solver_type()))) {
484SolveStatus MPSolverResponseStatusToSolveStatus(MPSolverResponseStatus s) {
486 case MPSOLVER_OPTIMAL:
488 case MPSOLVER_FEASIBLE:
490 case MPSOLVER_INFEASIBLE:
492 case MPSOLVER_UNBOUNDED:
494 case MPSOLVER_ABNORMAL:
496 case MPSOLVER_NOT_SOLVED:
498 case MPSOLVER_MODEL_IS_VALID:
500 case MPSOLVER_CANCELLED_BY_USER:
502 case MPSOLVER_UNKNOWN_STATUS:
504 case MPSOLVER_MODEL_INVALID:
506 case MPSOLVER_MODEL_INVALID_SOLUTION_HINT:
508 case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS:
510 case MPSOLVER_SOLVER_TYPE_UNAVAILABLE:
512 case MPSOLVER_INCOMPATIBLE_OPTIONS:
522 if (solver_name.empty())
return;
525 VLOG(1) <<
"Unsupported type " << solver_name;
527 solver_type_ =
static_cast<MPModelRequest::SolverType
>(parsed_type);
532 if (!solver_type_.has_value())
return false;
533 if (solver_type_.value() == MPModelRequest::GLOP_LINEAR_PROGRAMMING) {
537 if (solver_type_.value() == MPModelRequest::PDLP_LINEAR_PROGRAMMING) {
541 if (solver_type_.value() == MPModelRequest::SAT_INTEGER_PROGRAMMING) {
545 if (solver_type_.value() == MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING) {
550 if (solver_type_.value() == MPModelRequest::HIGHS_LINEAR_PROGRAMMING ||
551 solver_type_.value() == MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING) {
555 if (solver_type_.value() ==
556 MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING ||
557 solver_type_.value() == MPModelRequest::GUROBI_LINEAR_PROGRAMMING) {
560 if (solver_type_.value() ==
561 MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING ||
562 solver_type_.value() == MPModelRequest::XPRESS_LINEAR_PROGRAMMING) {
570 if (!solver_type_.has_value()) {
571 response_->set_status(
572 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
576 MPModelRequest request;
577 *request.mutable_model() = model.
model();
578 request.set_solver_type(solver_type_.value());
579 request.set_enable_internal_solver_output(solver_output_);
580 if (time_limit_in_second_.has_value()) {
581 request.set_solver_time_limit_seconds(time_limit_in_second_.value());
583 if (!solver_specific_parameters_.empty()) {
584 request.set_solver_specific_parameters(solver_specific_parameters_);
586 switch (solver_type_.value()) {
587 case MPModelRequest::GLOP_LINEAR_PROGRAMMING: {
589 GlopSolveProto(std::move(request), &interrupt_solve_, log_callback_);
592 case MPModelRequest::SAT_INTEGER_PROGRAMMING: {
593 response_ =
SatSolveProto(std::move(request), &interrupt_solve_,
594 log_callback_,
nullptr);
598 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING: {
603 response_ = std::move(temp.value());
609 case MPModelRequest::PDLP_LINEAR_PROGRAMMING: {
612 response_ = std::move(temp.value());
617 case MPModelRequest::
618 GUROBI_LINEAR_PROGRAMMING:
619 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING: {
622 response_ = std::move(temp.value());
626#if defined(USE_HIGHS)
627 case MPModelRequest::HIGHS_LINEAR_PROGRAMMING:
628 case MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING: {
633 response_ = std::move(temp.value());
638 case MPModelRequest::
639 XPRESS_LINEAR_PROGRAMMING:
640 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING: {
645 response_->set_status(
646 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
649 if (response_->status() == MPSOLVER_OPTIMAL ||
650 response_->status() == MPSOLVER_FEASIBLE) {
651 model_of_last_solve_ = &model.
model();
653 std::numeric_limits<double>::quiet_NaN());
660 std::function<
void(
const std::string&)> log_callback) {
661 log_callback_ = std::move(log_callback);
666 log_callback_ = [log_callback](
const std::string& message) {
674 interrupter_.Interrupt();
675 interrupt_solve_ =
true;
682 return response_.has_value() &&
683 (response_.value().
status() ==
684 MPSolverResponseStatus::MPSOLVER_OPTIMAL ||
685 response_.value().status() ==
686 MPSolverResponseStatus::MPSOLVER_FEASIBLE);
690 return response_.value();
694 if (!response_.has_value()) {
697 return MPSolverResponseStatusToSolveStatus(response_.value().status());
702 return response_.value().objective_value();
707 return response_.value().best_objective_bound();
712 if (var_index >= response_.value().variable_value_size())
return 0.0;
713 return response_.value().variable_value(var_index);
717 std::shared_ptr<LinearExpr> expr)
const {
720 evaluator_.AddToProcess(expr, 1.0);
721 return evaluator_.Evaluate();
726 if (var_index >= response_.value().reduced_cost_size())
return 0.0;
727 return response_.value().reduced_cost(var_index);
732 if (ct_index >= response_.value().dual_value_size())
return 0.0;
733 return response_.value().dual_value(ct_index);
737 if (!
has_response() || ct_index >= activities_.size() ||
738 !model_of_last_solve_.has_value()) {
742 if (std::isnan(activities_[ct_index])) {
743 const MPConstraintProto& ct_proto =
744 model_of_last_solve_.value()->constraint(ct_index);
746 for (
int i = 0; i < ct_proto.var_index_size(); ++i) {
747 result += response_->variable_value(ct_proto.var_index(i)) *
748 ct_proto.coefficient(i);
750 activities_[ct_index] = result;
752 return activities_[ct_index];
757 return response_.value().status_str();
761 if (!response_.has_value())
return 0.0;
762 if (!response_.value().has_solve_info())
return 0.0;
763 return response_.value().solve_info().solve_wall_time_seconds();
767 if (!response_.has_value())
return 0.0;
768 if (!response_.value().has_solve_info())
return 0.0;
769 return response_.value().solve_info().solve_user_time_seconds();
773 time_limit_in_second_ = limit;
777 const std::string& solver_specific_parameters) {
778 solver_specific_parameters_ = solver_specific_parameters;
786 return std::make_shared<AffineExpr>(expr, coeff, 0.0);
790 double coeff,
double constant) {
791 if (coeff == 1.0 && constant == 0.0)
return expr;
792 return std::make_shared<AffineExpr>(expr, coeff, constant);
797 return std::make_shared<FixedValue>(value * coeff + constant);
801 return std::make_shared<FixedValue>(value);
805 std::vector<std::shared_ptr<LinearExpr>> exprs;
806 exprs.push_back(shared_from_this());
807 exprs.push_back(expr);
808 return std::make_shared<SumArray>(exprs, 0.0);
812 if (cst == 0.0)
return shared_from_this();
813 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, cst);
817 std::vector<std::shared_ptr<LinearExpr>> exprs;
818 exprs.push_back(shared_from_this());
819 exprs.push_back(expr->MulFloat(-1.0));
820 return std::make_shared<SumArray>(exprs, 0.0);
824 if (cst == 0.0)
return shared_from_this();
825 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, -cst);
829 return std::make_shared<AffineExpr>(shared_from_this(), -1.0, cst);
833 if (cst == 0.0)
return std::make_shared<FixedValue>(0.0);
834 if (cst == 1.0)
return shared_from_this();
835 return std::make_shared<AffineExpr>(shared_from_this(), cst, 0.0);
839 return std::make_shared<AffineExpr>(shared_from_this(), -1, 0);
845 to_process_.push_back(std::make_pair(expr, coeff));
856 canonical_terms_[var] += coeff;
860 std::vector<double>* coeffs) {
864 expr->Visit(*
this, coeff);
869 for (
const auto& [var, coeff] : canonical_terms_) {
870 if (coeff == 0.0)
continue;
871 vars->push_back(var);
872 coeffs->push_back(coeff);
879 offset_ += coeff * helper_->variable_value(var->index());
887 expr->Visit(*
this, coeff);
895 offset_ = lin.
Flatten(&vars_, &coeffs_);
899 std::shared_ptr<LinearExpr> neg) {
903 offset_ = lin.
Flatten(&vars_, &coeffs_);
913 std::vector<int> var_indices;
914 var_indices.reserve(vars_.size());
915 for (
const std::shared_ptr<Variable>& var : vars_) {
916 var_indices.push_back(var->index());
922 for (
int i = 0; i < vars_.size(); ++i) {
930 return absl::StrCat(offset_);
934 for (
int i = 0; i < vars_.size(); ++i) {
935 DCHECK_NE(coeffs_[i], 0.0);
937 if (num_printed > 5) {
938 absl::StrAppend(&s,
" + ...");
941 if (num_printed == 1) {
942 if (coeffs_[i] == 1.0) {
943 absl::StrAppend(&s, vars_[i]->
ToString());
944 }
else if (coeffs_[i] == -1.0) {
945 absl::StrAppend(&s,
"-", vars_[i]->
ToString());
947 absl::StrAppend(&s, coeffs_[i],
" * ", vars_[i]->
ToString());
950 if (coeffs_[i] == 1.0) {
951 absl::StrAppend(&s,
" + ", vars_[i]->
ToString());
952 }
else if (coeffs_[i] == -1.0) {
953 absl::StrAppend(&s,
" - ", vars_[i]->
ToString());
954 }
else if (coeffs_[i] > 0.0) {
955 absl::StrAppend(&s,
" + ", coeffs_[i],
" * ", vars_[i]->
ToString());
957 absl::StrAppend(&s,
" - ", -coeffs_[i],
" * ", vars_[i]->
ToString());
962 if (num_printed == 0) {
963 return absl::StrCat(offset_);
967 if (offset_ != 0.0) {
969 absl::StrAppend(&s,
" + ", offset_);
971 absl::StrAppend(&s,
" - ", -offset_);
978 std::string s = absl::StrCat(
980 absl::StrJoin(vars_,
", ",
981 [](std::string* out, std::shared_ptr<Variable> expr) {
982 absl::StrAppend(out, expr->DebugString());
984 if (offset_ != 0.0) {
985 absl::StrAppend(&s,
", offset=", offset_);
987 absl::StrAppend(&s,
")");
993 : exprs_(
std::move(exprs)), offset_(
offset) {}
996 for (
int i = 0; i < exprs_.size(); ++i) {
999 if (offset_ != 0.0) {
1005 if (exprs_.empty()) {
1006 if (offset_ != 0.0) {
1007 return absl::StrCat(offset_);
1010 std::string s =
"(";
1011 for (
int i = 0; i < exprs_.size(); ++i) {
1013 absl::StrAppend(&s,
" + ");
1015 absl::StrAppend(&s, exprs_[i]->
ToString());
1017 if (offset_ != 0.0) {
1018 if (offset_ > 0.0) {
1019 absl::StrAppend(&s,
" + ", offset_);
1021 absl::StrAppend(&s,
" - ", -offset_);
1024 absl::StrAppend(&s,
")");
1029 std::string s = absl::StrCat(
1031 absl::StrJoin(exprs_,
", ",
1032 [](std::string* out, std::shared_ptr<LinearExpr> expr) {
1033 absl::StrAppend(out, expr->DebugString());
1035 if (offset_ != 0.0) {
1036 absl::StrAppend(&s,
", offset=", offset_);
1038 absl::StrAppend(&s,
")");
1043 std::shared_ptr<LinearExpr> expr) {
1044 exprs_.push_back(std::move(expr));
1045 return shared_from_this();
1050 return shared_from_this();
1064 return absl::StrCat(
"FixedValue(", value_,
")");
1068 const std::vector<std::shared_ptr<LinearExpr>>& exprs,
1069 const std::vector<double>& coeffs,
double offset)
1070 : exprs_(exprs.
begin(), exprs.
end()),
1071 coeffs_(coeffs.
begin(), coeffs.
end()),
1075 for (
int i = 0; i < exprs_.size(); ++i) {
1082 if (exprs_.empty()) {
1083 return absl::StrCat(offset_);
1085 std::string s =
"(";
1086 bool first_printed =
true;
1087 for (
int i = 0; i < exprs_.size(); ++i) {
1088 if (coeffs_[i] == 0.0)
continue;
1089 if (first_printed) {
1090 first_printed =
false;
1091 if (coeffs_[i] == 1.0) {
1092 absl::StrAppend(&s, exprs_[i]->
ToString());
1093 }
else if (coeffs_[i] == -1.0) {
1094 absl::StrAppend(&s,
"-", exprs_[i]->
ToString());
1096 absl::StrAppend(&s, coeffs_[i],
" * ", exprs_[i]->
ToString());
1099 if (coeffs_[i] == 1.0) {
1100 absl::StrAppend(&s,
" + ", exprs_[i]->
ToString());
1101 }
else if (coeffs_[i] == -1.0) {
1102 absl::StrAppend(&s,
" - ", exprs_[i]->
ToString());
1103 }
else if (coeffs_[i] > 0.0) {
1104 absl::StrAppend(&s,
" + ", coeffs_[i],
" * ", exprs_[i]->
ToString());
1106 absl::StrAppend(&s,
" - ", -coeffs_[i],
" * ", exprs_[i]->
ToString());
1111 if (first_printed) {
1112 return absl::StrCat(offset_);
1116 if (offset_ != 0.0) {
1117 if (offset_ > 0.0) {
1118 absl::StrAppend(&s,
" + ", offset_);
1120 absl::StrAppend(&s,
" - ", -offset_);
1123 absl::StrAppend(&s,
")");
1128 return absl::StrCat(
1129 "WeightedSumArray([",
1130 absl::StrJoin(exprs_,
", ",
1131 [](std::string* out, std::shared_ptr<LinearExpr> e) {
1132 absl::StrAppend(out, e->DebugString());
1134 "], [", absl::StrJoin(coeffs_,
"], "), offset_,
")");
1139 : expr_(expr), coeff_(coeff), offset_(
offset) {}
1147 if (cst == 0.0)
return shared_from_this();
1152 if (cst == 0.0)
return shared_from_this();
1161 if (cst == 0.0)
return std::make_shared<FixedValue>(0);
1162 if (cst == 1.0)
return shared_from_this();
1171 std::string s =
"(";
1172 if (coeff_ == 1.0) {
1173 absl::StrAppend(&s, expr_->ToString());
1174 }
else if (coeff_ == -1.0) {
1175 absl::StrAppend(&s,
"-", expr_->ToString());
1177 absl::StrAppend(&s, coeff_,
" * ", expr_->ToString());
1179 if (offset_ > 0.0) {
1180 absl::StrAppend(&s,
" + ", offset_);
1181 }
else if (offset_ < 0.0) {
1182 absl::StrAppend(&s,
" - ", -offset_);
1184 absl::StrAppend(&s,
")");
1189 return absl::StrCat(
"AffineExpr(expr=", expr_->DebugString(),
1190 ", coeff=", coeff_,
", offset=", offset_,
")");
1193 std::shared_ptr<LinearExpr> rhs) {
1194 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs, 0.0,
1199 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs,
1204 std::shared_ptr<LinearExpr> rhs) {
1205 return std::make_shared<BoundedLinearExpression>(
1206 shared_from_this(), rhs, -std::numeric_limits<double>::infinity(), 0.0);
1210 return std::make_shared<BoundedLinearExpression>(
1211 shared_from_this(), -std::numeric_limits<double>::infinity(), rhs);
1215 std::shared_ptr<LinearExpr> rhs) {
1216 return std::make_shared<BoundedLinearExpression>(
1217 shared_from_this(), rhs, 0.0, std::numeric_limits<double>::infinity());
1221 return std::make_shared<BoundedLinearExpression>(
1222 shared_from_this(), rhs, std::numeric_limits<double>::infinity());
1226 std::shared_ptr<Variable> rhs)
const {
1227 return lhs->index() < rhs->index();
1275 return absl::StrCat(
"Variable(",
index_,
")");
1280 return absl::StrCat(
"Variable(index=",
index_,
1289 if (!var_name.empty())
return var_name;
1290 return absl::StrCat(
"variable#",
index_);
1326 vars_ = flat_expr.
vars();
1327 coeffs_ = flat_expr.
coeffs();
1333 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1336 vars_ = flat_expr.
vars();
1337 coeffs_ = flat_expr.
coeffs();
1343 std::shared_ptr<LinearExpr> expr, int64_t
lower_bound,
1346 vars_ = flat_expr.
vars();
1347 coeffs_ = flat_expr.
coeffs();
1353 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1356 vars_ = flat_expr.
vars();
1357 coeffs_ = flat_expr.
coeffs();
1373 if (vars_.empty()) {
1374 s = absl::StrCat(0.0);
1375 }
else if (vars_.size() == 1) {
1376 const std::string var_name = vars_[0]->ToString();
1377 if (coeffs_[0] == 1) {
1379 }
else if (coeffs_[0] == -1) {
1380 s = absl::StrCat(
"-", var_name);
1382 s = absl::StrCat(coeffs_[0],
" * ", var_name);
1386 for (
int i = 0; i < vars_.size(); ++i) {
1387 const std::string var_name = vars_[i]->ToString();
1389 if (coeffs_[i] == 1) {
1390 absl::StrAppend(&s, var_name);
1391 }
else if (coeffs_[i] == -1) {
1392 absl::StrAppend(&s,
"-", var_name);
1394 absl::StrAppend(&s, coeffs_[i],
" * ", var_name);
1397 if (coeffs_[i] == 1) {
1398 absl::StrAppend(&s,
" + ", var_name);
1399 }
else if (coeffs_[i] == -1) {
1400 absl::StrAppend(&s,
" - ", var_name);
1401 }
else if (coeffs_[i] > 1) {
1402 absl::StrAppend(&s,
" + ", coeffs_[i],
" * ", var_name);
1404 absl::StrAppend(&s,
" - ", -coeffs_[i],
" * ", var_name);
1408 absl::StrAppend(&s,
")");
1410 if (lower_bound_ == upper_bound_) {
1411 return absl::StrCat(s,
" == ", lower_bound_);
1412 }
else if (lower_bound_ == -std::numeric_limits<double>::infinity()) {
1413 if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1414 return absl::StrCat(
"-inf <= ", s,
" <= inf");
1416 return absl::StrCat(s,
" <= ", upper_bound_);
1418 }
else if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1419 return absl::StrCat(s,
" >= ", lower_bound_);
1421 return absl::StrCat(lower_bound_,
" <= ", s,
" <= ", upper_bound_);
1426 return absl::StrCat(
1427 "BoundedLinearExpression(vars=[",
1428 absl::StrJoin(vars_,
", ",
1429 [](std::string* out, std::shared_ptr<Variable> var) {
1430 absl::StrAppend(out, var->DebugString());
1432 "], coeffs=[", absl::StrJoin(coeffs_,
", "),
1433 "], lower_bound=", lower_bound_,
", upper_bound=", upper_bound_,
")");
1437 const bool is_zero = lower_bound_ == 0.0 && upper_bound_ == 0.0;
1439 if (vars_.empty()) {
1442 }
else if (vars_.size() == 2 && coeffs_[0] + coeffs_[1] == 0 &&
1443 std::abs(coeffs_[0]) == 1) {
static bool SupportsProblemType(OptimizationProblemType problem_type)
static
static bool ParseSolverType(absl::string_view solver_id, OptimizationProblemType *type)
static
std::string ToString() const override
AffineExpr(std::shared_ptr< LinearExpr > expr, double coeff, double offset)
std::string DebugString() const override
std::shared_ptr< LinearExpr > Neg() override
std::shared_ptr< LinearExpr > SubFloat(double cst) override
std::shared_ptr< LinearExpr > RSubFloat(double cst) override
std::shared_ptr< LinearExpr > AddFloat(double cst) override
void Visit(ExprVisitor &lin, double c) override
std::shared_ptr< LinearExpr > MulFloat(double cst) override
std::string ToString() const
const std::vector< double > & coeffs() const
BoundedLinearExpression(std::shared_ptr< LinearExpr > expr, double lower_bound, double upper_bound)
bool CastToBool(bool *result) const
double lower_bound() const
double upper_bound() const
const std::vector< std::shared_ptr< Variable > > & vars() const
std::string DebugString() const
void AddVarCoeff(std::shared_ptr< Variable > var, double coeff) override
double Flatten(std::vector< std::shared_ptr< Variable > > *vars, std::vector< double > *coeffs)
void AddVarCoeff(std::shared_ptr< Variable > var, double coeff) override
A visitor class to parse a floating point linear expression.
std::vector< std::pair< std::shared_ptr< LinearExpr >, double > > to_process_
void AddToProcess(std::shared_ptr< LinearExpr > expr, double coeff)
Expression visitors.
virtual void AddVarCoeff(std::shared_ptr< Variable > var, double coeff)=0
void AddConstant(double constant)
std::string ToString() const override
void Visit(ExprVisitor &lin, double c) override
std::string DebugString() const override
A flat linear expression sum(vars[i] * coeffs[i]) + offset.
std::string ToString() const override
void Visit(ExprVisitor &lin, double c) override
const std::vector< std::shared_ptr< Variable > > & vars() const
FlatExpr(std::shared_ptr< LinearExpr > expr)
const std::vector< double > & coeffs() const
std::vector< int > VarIndices() const
std::string DebugString() const override
std::shared_ptr< LinearExpr > Add(std::shared_ptr< LinearExpr > expr)
std::shared_ptr< BoundedLinearExpression > Le(std::shared_ptr< LinearExpr > rhs)
std::shared_ptr< LinearExpr > Sub(std::shared_ptr< LinearExpr > expr)
std::shared_ptr< BoundedLinearExpression > EqCst(double rhs)
std::shared_ptr< BoundedLinearExpression > LeCst(double rhs)
static std::shared_ptr< LinearExpr > Affine(std::shared_ptr< LinearExpr > expr, double coeff, double constant)
static std::shared_ptr< LinearExpr > Constant(double value)
static std::shared_ptr< LinearExpr > AffineCst(double value, double coeff, double constant)
std::shared_ptr< BoundedLinearExpression > Ge(std::shared_ptr< LinearExpr > rhs)
virtual std::shared_ptr< LinearExpr > Neg()
virtual std::shared_ptr< LinearExpr > RSubFloat(double cst)
virtual std::shared_ptr< LinearExpr > AddFloat(double cst)
virtual std::shared_ptr< LinearExpr > MulFloat(double cst)
static std::shared_ptr< LinearExpr > Term(std::shared_ptr< LinearExpr > expr, double coeff)
Expressions.
std::shared_ptr< BoundedLinearExpression > GeCst(double rhs)
std::shared_ptr< BoundedLinearExpression > Eq(std::shared_ptr< LinearExpr > rhs)
virtual std::shared_ptr< LinearExpr > SubFloat(double cst)
Simple director class for C#.
virtual void NewMessage(const std::string &message)=0
void SetEnforcedConstraintLowerBound(int ct_index, double lb)
std::vector< int > ConstraintVarIndices(int ct_index) const
std::vector< double > EnforcedConstraintCoefficients(int ct_index) const
void SetVarIntegrality(int var_index, bool is_integer)
void ClearEnforcedConstraintTerms(int ct_index)
void SetEnforcedIndicatorValue(int ct_index, bool positive)
void SafeAddEnforcedConstraintTerm(int ct_index, int var_index, double coeff)
void SetEnforcedConstraintName(int ct_index, const std::string &name)
void SetVarName(int var_index, const std::string &name)
std::string VarName(int var_index) const
double EnforcedConstraintUpperBound(int ct_index) const
void AddConstraintTerm(int ct_index, int var_index, double coeff)
bool WriteToMpsFile(const std::string &filename, const operations_research::MPModelExportOptions &options=MPModelExportOptions())
int num_constraints() const
double ConstraintLowerBound(int ct_index) const
int AddEnforcedLinearConstraint()
int num_variables() const
bool ReadModelFromProtoFile(const std::string &filename)
std::string ExportToMpsString(const operations_research::MPModelExportOptions &options=MPModelExportOptions())
std::string ConstraintName(int ct_index) const
void SetVarUpperBound(int var_index, double ub)
bool EnforcedIndicatorValue(int ct_index) const
void SetObjectiveOffset(double offset)
void SetEnforcedConstraintCoefficient(int ct_index, int var_index, double coeff)
double VarObjectiveCoefficient(int var_index) const
std::string EnforcedConstraintName(int ct_index) const
void AddEnforcedConstraintTerm(int ct_index, int var_index, double coeff)
double ObjectiveOffset() const
double VarUpperBound(int var_index) const
double ConstraintUpperBound(int ct_index) const
MPModelProto * mutable_model()
void OverwriteModel(const ModelBuilderHelper &other_helper)
ModelBuilderHelper.
bool WriteModelToProtoFile(const std::string &filename)
void SetEnforcedIndicatorVariableIndex(int ct_index, int var_index)
void SetConstraintLowerBound(int ct_index, double lb)
bool ImportFromMpsFile(const std::string &mps_file)
void SetEnforcedConstraintUpperBound(int ct_index, double ub)
int AddLinearConstraint()
int EnforcedIndicatorVariableIndex(int ct_index) const
void AddHint(int var_index, double var_value)
void SetMaximize(bool maximize)
int AddVar()
Direct low level model building API.
void SetVarObjectiveCoefficient(int var_index, double coeff)
void SetVarLowerBound(int var_index, double lb)
void SetConstraintName(int ct_index, const std::string &name)
bool ImportFromMpsString(const std::string &mps_string)
bool VarIsIntegral(int var_index) const
bool IsEnforcedConstraint(int ct_index) const
bool ImportFromLpString(const std::string &lp_string)
bool ImportFromLpFile(const std::string &lp_file)
void SetConstraintUpperBound(int ct_index, double ub)
std::vector< double > ConstraintCoefficients(int ct_index) const
const MPModelProto & model() const
double VarLowerBound(int var_index) const
void SafeAddConstraintTerm(int ct_index, int var_index, double coeff)
void ClearConstraintTerms(int ct_index)
void SetConstraintCoefficient(int ct_index, int var_index, double coeff)
void SetName(const std::string &name)
std::string ExportToLpString(const operations_research::MPModelExportOptions &options=MPModelExportOptions())
double EnforcedConstraintLowerBound(int ct_index) const
std::vector< int > EnforcedConstraintVarIndices(int ct_index) const
void Solve(const ModelBuilderHelper &model)
void SetSolverSpecificParameters(const std::string &solver_specific_parameters)
double variable_value(int var_index) const
ModelSolverHelper(const std::string &solver_name)
std::string status_string() const
bool has_response() const
std::optional< MPSolutionResponse > SolveRequest(const MPModelRequest &request)
Only used by the CVXPY interface. Does not store the response internally.
double objective_value() const
If not defined, or no solution, they will silently return 0.
bool SolverIsSupported() const
double activity(int ct_index)
const MPSolutionResponse & response() const
void SetLogCallbackFromDirectorClass(MbLogCallback *log_callback)
bool has_solution() const
double expression_value(std::shared_ptr< LinearExpr > expr) const
double best_objective_bound() const
void EnableOutput(bool enabled)
void SetTimeLimitInSeconds(double limit)
Solve parameters.
double reduced_cost(int var_index) const
void SetLogCallback(std::function< void(const std::string &)> log_callback)
SolveStatus status() const
double dual_value(int ct_index) const
void Visit(ExprVisitor &lin, double c) override
std::shared_ptr< LinearExpr > AddInPlace(std::shared_ptr< LinearExpr > expr)
std::string ToString() const override
std::shared_ptr< LinearExpr > AddFloatInPlace(double cst)
std::string DebugString() const override
SumArray(std::vector< std::shared_ptr< LinearExpr > > exprs, double offset)
Variable(ModelBuilderHelper *helper, int index)
void SetLowerBound(double lb)
double upper_bound() const
double lower_bounds() const
ModelBuilderHelper * helper_
void SetName(const std::string &name)
ModelBuilderHelper * helper() const
std::string DebugString() const override
void SetObjectiveCoefficient(double coeff)
std::string ToString() const override
double objective_coefficient() const
void SetUpperBound(double ub)
void SetIsIntegral(bool is_integral)
std::string ToString() const override
WeightedSumArray(const std::vector< std::shared_ptr< LinearExpr > > &exprs, const std::vector< double > &coeffs, double offset)
void Visit(ExprVisitor &lin, double c) override
std::string DebugString() const override
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
-— Content API -—
absl::Status SetBinaryProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
absl::Status SetTextProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
absl::Status GetTextProto(absl::string_view file_name, google::protobuf::Message *proto, Options options)
-— Protobuf API -—
absl::Status GetBinaryProto(const absl::string_view file_name, google::protobuf::Message *proto, Options options)
absl::StatusOr< MPModelProto > MpsFileToMPModelProto(absl::string_view mps_file)
Parses an MPS model from a file.
absl::StatusOr< MPModelProto > MpsDataToMPModelProto(absl::string_view mps_data)
Parses an MPS model from a string.
@ SOLVER_TYPE_UNAVAILABLE
@ INVALID_SOLVER_PARAMETERS
In SWIG mode, we don't want anything besides these top-level includes.
MPSolutionResponse SatSolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> logging_callback, std::function< void(const MPSolution &)> solution_callback)
absl::Status WriteModelToMpsFile(absl::string_view filename, const MPModelProto &model, const MPModelExportOptions &options)
MPSolutionResponse SolveMPModel(LazyMutableCopy< MPModelRequest > request, const SolveInterrupter *interrupter)
absl::StatusOr< MPSolutionResponse > PdlpSolveProto(LazyMutableCopy< MPModelRequest > request, const bool relax_integer_variables, const std::atomic< bool > *interrupt_solve)
absl::StatusOr< std::string > ExportModelAsLpFormat(const MPModelProto &model, const MPModelExportOptions &options)
bool GurobiIsCorrectlyInstalled()
absl::StatusOr< MPSolutionResponse > ScipSolveProto(LazyMutableCopy< MPModelRequest > request)
ClosedInterval::Iterator end(ClosedInterval interval)
MPSolutionResponse GlopSolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> logging_callback)
bool XpressIsCorrectlyInstalled()
absl::StatusOr< MPSolutionResponse > GurobiSolveProto(LazyMutableCopy< MPModelRequest > request, GRBenv *gurobi_env)
absl::StatusOr< MPSolutionResponse > HighsSolveProto(LazyMutableCopy< MPModelRequest > request)
Solve the input MIP model with the HIGHS solver.
absl::StatusOr< std::string > ExportModelAsMpsFormat(const MPModelProto &model, const MPModelExportOptions &options)
ClosedInterval::Iterator begin(ClosedInterval interval)
absl::StatusOr< MPModelProto > ModelProtoFromLpFormat(absl::string_view model)
This calls ParseLp() under the hood. See below.
MPSolutionResponse XPressSolveProto(LazyMutableCopy< MPModelRequest > request)
Solves the input request.
bool operator()(std::shared_ptr< Variable > lhs, std::shared_ptr< Variable > rhs) const