26#include "absl/log/check.h"
27#include "absl/strings/match.h"
28#include "absl/strings/str_cat.h"
29#include "absl/strings/str_join.h"
35#include "ortools/linear_solver/linear_solver.pb.h"
51#if defined(USE_LP_PARSER)
64 model_ = other_helper.
model();
89 MPModelRequest request;
92 model_ = request.model();
99 if (absl::EndsWith(filename,
"txt")) {
109 absl::StatusOr<MPModelProto> model_or =
111 if (!model_or.ok())
return false;
112 model_ = model_or.value();
117 absl::StatusOr<MPModelProto> model_or =
119 if (!model_or.ok())
return false;
120 model_ = model_or.value();
124#if defined(USE_LP_PARSER)
125bool ModelBuilderHelper::ImportFromLpString(
const std::string& lp_string) {
126 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_string);
127 if (!model_or.ok())
return false;
128 model_ = model_or.value();
132bool ModelBuilderHelper::ImportFromLpFile(
const std::string& lp_file) {
137 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_data);
138 if (!model_or.ok())
return false;
139 model_ = model_or.value();
149 const int index = model_.variable_size();
150 model_.add_variable();
155 model_.mutable_variable(var_index)->set_lower_bound(lb);
159 model_.mutable_variable(var_index)->set_upper_bound(ub);
163 model_.mutable_variable(var_index)->set_is_integer(is_integer);
168 model_.mutable_variable(var_index)->set_objective_coefficient(coeff);
172 model_.mutable_variable(var_index)->set_name(
name);
176 return model_.variable(var_index).lower_bound();
180 return model_.variable(var_index).upper_bound();
184 return model_.variable(var_index).is_integer();
188 return model_.variable(var_index).objective_coefficient();
192 return model_.variable(var_index).name();
196 const int index = model_.constraint_size();
197 model_.add_constraint();
202 model_.mutable_constraint(ct_index)->set_lower_bound(lb);
206 model_.mutable_constraint(ct_index)->set_upper_bound(ub);
210 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
211 ct_proto->clear_var_index();
212 ct_proto->clear_coefficient();
217 if (coeff == 0.0)
return;
218 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
219 ct_proto->add_var_index(var_index);
220 ct_proto->add_coefficient(coeff);
225 if (coeff == 0.0)
return;
226 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
227 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
228 if (ct_proto->var_index(i) == var_index) {
229 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
235 ct_proto->add_var_index(var_index);
236 ct_proto->add_coefficient(coeff);
240 const std::string&
name) {
241 model_.mutable_constraint(ct_index)->set_name(
name);
246 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
247 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
248 if (ct_proto->var_index(i) == var_index) {
249 ct_proto->set_coefficient(i, coeff);
255 ct_proto->add_var_index(var_index);
256 ct_proto->add_coefficient(coeff);
260 return model_.constraint(ct_index).lower_bound();
264 return model_.constraint(ct_index).upper_bound();
268 return model_.constraint(ct_index).name();
272 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
273 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
277 int ct_index)
const {
278 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
279 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
283 const int index = model_.general_constraint_size();
285 model_.add_general_constraint()->mutable_indicator_constraint();
290 const MPGeneralConstraintProto& gen = model_.general_constraint(ct_index);
291 return gen.general_constraint_case() ==
292 MPGeneralConstraintProto::kIndicatorConstraint;
298 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
299 MPConstraintProto* ct_proto =
300 gen->mutable_indicator_constraint()->mutable_constraint();
301 ct_proto->set_lower_bound(lb);
307 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
308 MPConstraintProto* ct_proto =
309 gen->mutable_indicator_constraint()->mutable_constraint();
310 ct_proto->set_upper_bound(ub);
314 MPConstraintProto* ct_proto = model_.mutable_general_constraint(ct_index)
315 ->mutable_indicator_constraint()
316 ->mutable_constraint();
317 ct_proto->clear_var_index();
318 ct_proto->clear_coefficient();
324 if (coeff == 0.0)
return;
325 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
326 MPConstraintProto* ct_proto =
327 gen->mutable_indicator_constraint()->mutable_constraint();
328 ct_proto->add_var_index(var_index);
329 ct_proto->add_coefficient(coeff);
336 if (coeff == 0.0)
return;
337 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
338 MPConstraintProto* ct_proto =
339 gen->mutable_indicator_constraint()->mutable_constraint();
340 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
341 if (ct_proto->var_index(i) == var_index) {
342 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
348 ct_proto->add_var_index(var_index);
349 ct_proto->add_coefficient(coeff);
353 const std::string&
name) {
354 model_.mutable_general_constraint(ct_index)->set_name(
name);
361 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
362 MPConstraintProto* ct_proto =
363 gen->mutable_indicator_constraint()->mutable_constraint();
364 for (
int i = 0; i < ct_proto->var_index_size(); ++i) {
365 if (ct_proto->var_index(i) == var_index) {
366 ct_proto->set_coefficient(i, coeff);
372 ct_proto->add_var_index(var_index);
373 ct_proto->add_coefficient(coeff);
379 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
380 gen->mutable_indicator_constraint()->set_var_index(var_index);
386 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
387 gen->mutable_indicator_constraint()->set_var_value(positive);
392 return model_.general_constraint(ct_index)
393 .indicator_constraint()
400 return model_.general_constraint(ct_index)
401 .indicator_constraint()
408 return model_.general_constraint(ct_index).name();
412 int ct_index)
const {
414 const MPConstraintProto& ct_proto =
415 model_.general_constraint(ct_index).indicator_constraint().constraint();
416 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
420 int ct_index)
const {
422 const MPConstraintProto& ct_proto =
423 model_.general_constraint(ct_index).indicator_constraint().constraint();
424 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
429 return model_.general_constraint(ct_index).indicator_constraint().var_index();
434 return model_.general_constraint(ct_index)
435 .indicator_constraint()
442 return model_.constraint_size() + model_.general_constraint_size();
448 model_.set_name(
name);
451 for (MPVariableProto& var : *model_.mutable_variable()) {
452 var.clear_objective_coefficient();
463 return model_.objective_offset();
467 model_.set_objective_offset(offset);
473 model_.mutable_solution_hint()->add_var_index(var_index);
474 model_.mutable_solution_hint()->add_var_value(var_value);
478 const MPModelRequest& request) {
481 request.solver_type()))) {
488SolveStatus MPSolverResponseStatusToSolveStatus(MPSolverResponseStatus s) {
490 case MPSOLVER_OPTIMAL:
492 case MPSOLVER_FEASIBLE:
494 case MPSOLVER_INFEASIBLE:
496 case MPSOLVER_UNBOUNDED:
498 case MPSOLVER_ABNORMAL:
500 case MPSOLVER_NOT_SOLVED:
502 case MPSOLVER_MODEL_IS_VALID:
504 case MPSOLVER_CANCELLED_BY_USER:
506 case MPSOLVER_UNKNOWN_STATUS:
508 case MPSOLVER_MODEL_INVALID:
510 case MPSOLVER_MODEL_INVALID_SOLUTION_HINT:
512 case MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS:
514 case MPSOLVER_SOLVER_TYPE_UNAVAILABLE:
516 case MPSOLVER_INCOMPATIBLE_OPTIONS:
526 if (solver_name.empty())
return;
529 VLOG(1) <<
"Unsupported type " << solver_name;
531 solver_type_ =
static_cast<MPModelRequest::SolverType
>(parsed_type);
536 if (!solver_type_.has_value())
return false;
537 if (solver_type_.value() == MPModelRequest::GLOP_LINEAR_PROGRAMMING) {
541 if (solver_type_.value() == MPModelRequest::PDLP_LINEAR_PROGRAMMING) {
545 if (solver_type_.value() == MPModelRequest::SAT_INTEGER_PROGRAMMING) {
549 if (solver_type_.value() == MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING) {
554 if (solver_type_.value() == MPModelRequest::HIGHS_LINEAR_PROGRAMMING ||
555 solver_type_.value() == MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING) {
559 if (solver_type_.value() ==
560 MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING ||
561 solver_type_.value() == MPModelRequest::GUROBI_LINEAR_PROGRAMMING) {
564 if (solver_type_.value() ==
565 MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING ||
566 solver_type_.value() == MPModelRequest::XPRESS_LINEAR_PROGRAMMING) {
574 if (!solver_type_.has_value()) {
575 response_->set_status(
576 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
580 MPModelRequest request;
581 *request.mutable_model() = model.
model();
582 request.set_solver_type(solver_type_.value());
583 request.set_enable_internal_solver_output(solver_output_);
584 if (time_limit_in_second_.has_value()) {
585 request.set_solver_time_limit_seconds(time_limit_in_second_.value());
587 if (!solver_specific_parameters_.empty()) {
588 request.set_solver_specific_parameters(solver_specific_parameters_);
590 switch (solver_type_.value()) {
591 case MPModelRequest::GLOP_LINEAR_PROGRAMMING: {
593 GlopSolveProto(std::move(request), &interrupt_solve_, log_callback_);
596 case MPModelRequest::SAT_INTEGER_PROGRAMMING: {
597 response_ =
SatSolveProto(std::move(request), &interrupt_solve_,
598 log_callback_,
nullptr);
602 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING: {
607 response_ = std::move(temp.value());
613 case MPModelRequest::PDLP_LINEAR_PROGRAMMING: {
616 response_ = std::move(temp.value());
621 case MPModelRequest::
622 GUROBI_LINEAR_PROGRAMMING:
623 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING: {
626 response_ = std::move(temp.value());
630#if defined(USE_HIGHS)
631 case MPModelRequest::HIGHS_LINEAR_PROGRAMMING:
632 case MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING: {
637 response_ = std::move(temp.value());
642 case MPModelRequest::
643 XPRESS_LINEAR_PROGRAMMING:
644 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING: {
649 response_->set_status(
650 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
653 if (response_->status() == MPSOLVER_OPTIMAL ||
654 response_->status() == MPSOLVER_FEASIBLE) {
655 model_of_last_solve_ = &model.
model();
657 std::numeric_limits<double>::quiet_NaN());
664 std::function<
void(
const std::string&)> log_callback) {
665 log_callback_ = std::move(log_callback);
670 log_callback_ = [log_callback](
const std::string& message) {
678 interrupter_.Interrupt();
679 interrupt_solve_ =
true;
686 return response_.has_value() &&
687 (response_.value().
status() ==
688 MPSolverResponseStatus::MPSOLVER_OPTIMAL ||
689 response_.value().status() ==
690 MPSolverResponseStatus::MPSOLVER_FEASIBLE);
694 return response_.value();
698 if (!response_.has_value()) {
701 return MPSolverResponseStatusToSolveStatus(response_.value().status());
706 return response_.value().objective_value();
711 return response_.value().best_objective_bound();
716 if (var_index >= response_.value().variable_value_size())
return 0.0;
717 return response_.value().variable_value(var_index);
721 std::shared_ptr<LinearExpr> expr)
const {
724 evaluator_.AddToProcess(expr, 1.0);
725 return evaluator_.Evaluate();
730 if (var_index >= response_.value().reduced_cost_size())
return 0.0;
731 return response_.value().reduced_cost(var_index);
736 if (ct_index >= response_.value().dual_value_size())
return 0.0;
737 return response_.value().dual_value(ct_index);
741 if (!
has_response() || ct_index >= activities_.size() ||
742 !model_of_last_solve_.has_value()) {
746 if (std::isnan(activities_[ct_index])) {
747 const MPConstraintProto& ct_proto =
748 model_of_last_solve_.value()->constraint(ct_index);
750 for (
int i = 0; i < ct_proto.var_index_size(); ++i) {
751 result += response_->variable_value(ct_proto.var_index(i)) *
752 ct_proto.coefficient(i);
754 activities_[ct_index] = result;
756 return activities_[ct_index];
761 return response_.value().status_str();
765 if (!response_.has_value())
return 0.0;
766 if (!response_.value().has_solve_info())
return 0.0;
767 return response_.value().solve_info().solve_wall_time_seconds();
771 if (!response_.has_value())
return 0.0;
772 if (!response_.value().has_solve_info())
return 0.0;
773 return response_.value().solve_info().solve_user_time_seconds();
777 time_limit_in_second_ = limit;
781 const std::string& solver_specific_parameters) {
782 solver_specific_parameters_ = solver_specific_parameters;
790 return std::make_shared<AffineExpr>(expr, coeff, 0.0);
794 double coeff,
double constant) {
795 if (coeff == 1.0 && constant == 0.0)
return expr;
796 return std::make_shared<AffineExpr>(expr, coeff, constant);
801 return std::make_shared<FixedValue>(value * coeff + constant);
805 return std::make_shared<FixedValue>(value);
809 std::vector<std::shared_ptr<LinearExpr>> exprs;
810 exprs.push_back(shared_from_this());
811 exprs.push_back(expr);
812 return std::make_shared<SumArray>(exprs, 0.0);
816 if (cst == 0.0)
return shared_from_this();
817 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, cst);
821 std::vector<std::shared_ptr<LinearExpr>> exprs;
822 exprs.push_back(shared_from_this());
823 exprs.push_back(expr);
824 std::vector<double> coeffs = {1.0, -1.0};
825 return std::make_shared<WeightedSumArray>(exprs, coeffs, 0.0);
829 if (cst == 0.0)
return shared_from_this();
830 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, -cst);
834 return std::make_shared<AffineExpr>(shared_from_this(), -1.0, cst);
838 if (cst == 0.0)
return std::make_shared<FixedValue>(0.0);
839 if (cst == 1.0)
return shared_from_this();
840 return std::make_shared<AffineExpr>(shared_from_this(), cst, 0.0);
844 return std::make_shared<AffineExpr>(shared_from_this(), -1, 0);
850 to_process_.push_back(std::make_pair(expr, coeff));
861 canonical_terms_[var] += coeff;
865 std::vector<double>* coeffs) {
869 expr->Visit(*
this, coeff);
874 for (
const auto& [var, coeff] : canonical_terms_) {
875 if (coeff == 0.0)
continue;
876 vars->push_back(var);
877 coeffs->push_back(coeff);
884 offset_ += coeff * helper_->variable_value(var->index());
892 expr->Visit(*
this, coeff);
900 offset_ = lin.
Flatten(&vars_, &coeffs_);
904 std::shared_ptr<LinearExpr> neg) {
908 offset_ = lin.
Flatten(&vars_, &coeffs_);
918 std::vector<int> var_indices;
919 var_indices.reserve(vars_.size());
920 for (
const std::shared_ptr<Variable>& var : vars_) {
921 var_indices.push_back(var->index());
927 for (
int i = 0; i < vars_.size(); ++i) {
935 return absl::StrCat(offset_);
939 for (
int i = 0; i < vars_.size(); ++i) {
940 DCHECK_NE(coeffs_[i], 0.0);
942 if (num_printed > 5) {
943 absl::StrAppend(&s,
" + ...");
946 if (num_printed == 1) {
947 if (coeffs_[i] == 1.0) {
948 absl::StrAppend(&s, vars_[i]->
ToString());
949 }
else if (coeffs_[i] == -1.0) {
950 absl::StrAppend(&s,
"-", vars_[i]->
ToString());
952 absl::StrAppend(&s, coeffs_[i],
" * ", vars_[i]->
ToString());
955 if (coeffs_[i] == 1.0) {
956 absl::StrAppend(&s,
" + ", vars_[i]->
ToString());
957 }
else if (coeffs_[i] == -1.0) {
958 absl::StrAppend(&s,
" - ", vars_[i]->
ToString());
959 }
else if (coeffs_[i] > 0.0) {
960 absl::StrAppend(&s,
" + ", coeffs_[i],
" * ", vars_[i]->
ToString());
962 absl::StrAppend(&s,
" - ", -coeffs_[i],
" * ", vars_[i]->
ToString());
967 if (num_printed == 0) {
968 return absl::StrCat(offset_);
972 if (offset_ != 0.0) {
974 absl::StrAppend(&s,
" + ", offset_);
976 absl::StrAppend(&s,
" - ", -offset_);
983 std::string s = absl::StrCat(
985 absl::StrJoin(vars_,
", ",
986 [](std::string* out, std::shared_ptr<Variable> expr) {
987 absl::StrAppend(out, expr->DebugString());
989 if (offset_ != 0.0) {
990 absl::StrAppend(&s,
", offset=", offset_);
992 absl::StrAppend(&s,
")");
1003 return absl::StrCat(
"FixedValue(", value_,
")");
1007 const std::vector<std::shared_ptr<LinearExpr>>& exprs,
1008 const std::vector<double>& coeffs,
double offset)
1009 : exprs_(exprs.begin(), exprs.end()),
1010 coeffs_(coeffs.begin(), coeffs.end()),
1014 for (
int i = 0; i < exprs_.size(); ++i) {
1021 if (exprs_.empty()) {
1022 return absl::StrCat(offset_);
1024 std::string s =
"(";
1025 bool first_printed =
true;
1026 for (
int i = 0; i < exprs_.size(); ++i) {
1027 if (coeffs_[i] == 0.0)
continue;
1028 if (first_printed) {
1029 first_printed =
false;
1030 if (coeffs_[i] == 1.0) {
1031 absl::StrAppend(&s, exprs_[i]->
ToString());
1032 }
else if (coeffs_[i] == -1.0) {
1033 absl::StrAppend(&s,
"-", exprs_[i]->
ToString());
1035 absl::StrAppend(&s, coeffs_[i],
" * ", exprs_[i]->
ToString());
1038 if (coeffs_[i] == 1.0) {
1039 absl::StrAppend(&s,
" + ", exprs_[i]->
ToString());
1040 }
else if (coeffs_[i] == -1.0) {
1041 absl::StrAppend(&s,
" - ", exprs_[i]->
ToString());
1042 }
else if (coeffs_[i] > 0.0) {
1043 absl::StrAppend(&s,
" + ", coeffs_[i],
" * ", exprs_[i]->
ToString());
1045 absl::StrAppend(&s,
" - ", -coeffs_[i],
" * ", exprs_[i]->
ToString());
1050 if (first_printed) {
1051 return absl::StrCat(offset_);
1055 if (offset_ != 0.0) {
1056 if (offset_ > 0.0) {
1057 absl::StrAppend(&s,
" + ", offset_);
1059 absl::StrAppend(&s,
" - ", -offset_);
1062 absl::StrAppend(&s,
")");
1067 return absl::StrCat(
1068 "WeightedSumArray([",
1069 absl::StrJoin(exprs_,
", ",
1070 [](std::string* out, std::shared_ptr<LinearExpr> e) {
1071 absl::StrAppend(out, e->DebugString());
1073 "], [", absl::StrJoin(coeffs_,
"], "), offset_,
")");
1078 : expr_(expr), coeff_(coeff), offset_(
offset) {}
1086 if (cst == 0.0)
return shared_from_this();
1091 if (cst == 0.0)
return shared_from_this();
1100 if (cst == 0.0)
return std::make_shared<FixedValue>(0);
1101 if (cst == 1.0)
return shared_from_this();
1110 std::string s =
"(";
1111 if (coeff_ == 1.0) {
1112 absl::StrAppend(&s, expr_->ToString());
1113 }
else if (coeff_ == -1.0) {
1114 absl::StrAppend(&s,
"-", expr_->ToString());
1116 absl::StrAppend(&s, coeff_,
" * ", expr_->ToString());
1118 if (offset_ > 0.0) {
1119 absl::StrAppend(&s,
" + ", offset_);
1120 }
else if (offset_ < 0.0) {
1121 absl::StrAppend(&s,
" - ", -offset_);
1123 absl::StrAppend(&s,
")");
1128 return absl::StrCat(
"AffineExpr(expr=", expr_->DebugString(),
1129 ", coeff=", coeff_,
", offset=", offset_,
")");
1132 std::shared_ptr<LinearExpr> rhs) {
1133 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs, 0.0,
1138 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs,
1143 std::shared_ptr<LinearExpr> rhs) {
1144 return std::make_shared<BoundedLinearExpression>(
1145 shared_from_this(), rhs, -std::numeric_limits<double>::infinity(), 0.0);
1149 return std::make_shared<BoundedLinearExpression>(
1150 shared_from_this(), -std::numeric_limits<double>::infinity(), rhs);
1154 std::shared_ptr<LinearExpr> rhs) {
1155 return std::make_shared<BoundedLinearExpression>(
1156 shared_from_this(), rhs, 0.0, std::numeric_limits<double>::infinity());
1160 return std::make_shared<BoundedLinearExpression>(
1161 shared_from_this(), rhs, std::numeric_limits<double>::infinity());
1165 std::shared_ptr<Variable> rhs)
const {
1166 return lhs->index() < rhs->index();
1214 return absl::StrCat(
"Variable(",
index_,
")");
1219 return absl::StrCat(
"Variable(index=",
index_,
1228 if (!var_name.empty())
return var_name;
1229 return absl::StrCat(
"variable#",
index_);
1265 vars_ = flat_expr.
vars();
1266 coeffs_ = flat_expr.
coeffs();
1272 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1275 vars_ = flat_expr.
vars();
1276 coeffs_ = flat_expr.
coeffs();
1282 std::shared_ptr<LinearExpr> expr, int64_t
lower_bound,
1285 vars_ = flat_expr.
vars();
1286 coeffs_ = flat_expr.
coeffs();
1292 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1295 vars_ = flat_expr.
vars();
1296 coeffs_ = flat_expr.
coeffs();
1312 if (vars_.empty()) {
1313 s = absl::StrCat(0.0);
1314 }
else if (vars_.size() == 1) {
1315 const std::string var_name = vars_[0]->ToString();
1316 if (coeffs_[0] == 1) {
1318 }
else if (coeffs_[0] == -1) {
1319 s = absl::StrCat(
"-", var_name);
1321 s = absl::StrCat(coeffs_[0],
" * ", var_name);
1325 for (
int i = 0; i < vars_.size(); ++i) {
1326 const std::string var_name = vars_[i]->ToString();
1328 if (coeffs_[i] == 1) {
1329 absl::StrAppend(&s, var_name);
1330 }
else if (coeffs_[i] == -1) {
1331 absl::StrAppend(&s,
"-", var_name);
1333 absl::StrAppend(&s, coeffs_[i],
" * ", var_name);
1336 if (coeffs_[i] == 1) {
1337 absl::StrAppend(&s,
" + ", var_name);
1338 }
else if (coeffs_[i] == -1) {
1339 absl::StrAppend(&s,
" - ", var_name);
1340 }
else if (coeffs_[i] > 1) {
1341 absl::StrAppend(&s,
" + ", coeffs_[i],
" * ", var_name);
1343 absl::StrAppend(&s,
" - ", -coeffs_[i],
" * ", var_name);
1347 absl::StrAppend(&s,
")");
1349 if (lower_bound_ == upper_bound_) {
1350 return absl::StrCat(s,
" == ", lower_bound_);
1351 }
else if (lower_bound_ == -std::numeric_limits<double>::infinity()) {
1352 if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1353 return absl::StrCat(
"-inf <= ", s,
" <= inf");
1355 return absl::StrCat(s,
" <= ", upper_bound_);
1357 }
else if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1358 return absl::StrCat(s,
" >= ", lower_bound_);
1360 return absl::StrCat(lower_bound_,
" <= ", s,
" <= ", upper_bound_);
1365 return absl::StrCat(
1366 "BoundedLinearExpression(vars=[",
1367 absl::StrJoin(vars_,
", ",
1368 [](std::string* out, std::shared_ptr<Variable> var) {
1369 absl::StrAppend(out, var->DebugString());
1371 "], coeffs=[", absl::StrJoin(coeffs_,
", "),
1372 "], lower_bound=", lower_bound_,
", upper_bound=", upper_bound_,
")");
1376 const bool is_zero = lower_bound_ == 0.0 && upper_bound_ == 0.0;
1378 if (vars_.empty()) {
1381 }
else if (vars_.size() == 2 && coeffs_[0] + coeffs_[1] == 0 &&
1382 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()
std::shared_ptr< LinearExpr > AddFloat(double cst)
std::shared_ptr< LinearExpr > RSubFloat(double cst)
void Visit(ExprVisitor &lin, double c) override
std::shared_ptr< LinearExpr > MulFloat(double cst)
std::shared_ptr< LinearExpr > SubFloat(double cst)
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)
std::shared_ptr< LinearExpr > Neg()
std::shared_ptr< LinearExpr > RSubFloat(double cst)
std::shared_ptr< LinearExpr > AddFloat(double cst)
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)
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
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
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::Status SetTextProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
absl::Status SetBinaryProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
absl::Status GetTextProto(absl::string_view filename, google::protobuf::Message *proto, Options options)
absl::Status GetBinaryProto(const absl::string_view filename, 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)
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)
MPSolutionResponse XPressSolveProto(LazyMutableCopy< MPModelRequest > request)
Solves the input request.
bool operator()(std::shared_ptr< Variable > lhs, std::shared_ptr< Variable > rhs) const