Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
model_builder_helper.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <cmath>
17#include <cstdint>
18#include <functional>
19#include <limits>
20#include <memory>
21#include <optional>
22#include <string>
23#include <utility>
24#include <vector>
25
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"
41#if defined(USE_SCIP)
43#endif // defined(USE_SCIP)
44#if defined(USE_HIGHS)
46#endif // defined(USE_HIGHS)
47#if defined(USE_PDLP)
49#endif // defined(USE_PDLP)
52
53namespace operations_research {
54namespace mb {
55
56// ModelBuilderHelper.
57
59 const ModelBuilderHelper& other_helper) {
60 model_ = other_helper.model();
61}
62
64 const MPModelExportOptions& options) {
66 .value_or("");
67}
68
70 const MPModelExportOptions& options) {
71 return operations_research::ExportModelAsLpFormat(model_, options)
72 .value_or("");
73}
74
75bool ModelBuilderHelper::WriteToMpsFile(const std::string& filename,
76 const MPModelExportOptions& options) {
77 return WriteModelToMpsFile(filename, model_, options).ok();
78}
79
80bool ModelBuilderHelper::ReadModelFromProtoFile(const std::string& filename) {
81 if (file::GetTextProto(filename, &model_, file::Defaults()).ok() ||
82 file::GetBinaryProto(filename, &model_, file::Defaults()).ok()) {
83 return true;
84 }
85 MPModelRequest request;
86 if (file::GetTextProto(filename, &request, file::Defaults()).ok() ||
87 file::GetBinaryProto(filename, &request, file::Defaults()).ok()) {
88 model_ = request.model();
89 return true;
90 }
91 return false;
92}
93
94bool ModelBuilderHelper::WriteModelToProtoFile(const std::string& filename) {
95 if (absl::EndsWith(filename, "txt")) {
96 return file::SetTextProto(filename, model_, file::Defaults()).ok();
97 } else {
98 return file::SetBinaryProto(filename, model_, file::Defaults()).ok();
99 }
100}
101
102// See comment in the header file why we need to wrap absl::Status code with
103// code having simpler APIs.
104bool ModelBuilderHelper::ImportFromMpsString(const std::string& mps_string) {
105 absl::StatusOr<MPModelProto> model_or =
107 if (!model_or.ok()) return false;
108 model_ = model_or.value();
109 return true;
110}
111
112bool ModelBuilderHelper::ImportFromMpsFile(const std::string& mps_file) {
113 absl::StatusOr<MPModelProto> model_or =
115 if (!model_or.ok()) return false;
116 model_ = model_or.value();
117 return true;
118}
119
120bool ModelBuilderHelper::ImportFromLpString(const std::string& lp_string) {
121 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_string);
122 if (!model_or.ok()) return false;
123 model_ = model_or.value();
124 return true;
125}
126
127bool ModelBuilderHelper::ImportFromLpFile(const std::string& lp_file) {
128 std::string lp_data;
129 if (!file::GetContents(lp_file, &lp_data, file::Defaults()).ok()) {
130 return false;
131 }
132 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_data);
133 if (!model_or.ok()) return false;
134 model_ = model_or.value();
135 return true;
136}
137
138const MPModelProto& ModelBuilderHelper::model() const { return model_; }
139
141
143 const int index = model_.variable_size();
144 model_.add_variable();
145 return index;
146}
147
148void ModelBuilderHelper::SetVarLowerBound(int var_index, double lb) {
149 model_.mutable_variable(var_index)->set_lower_bound(lb);
150}
151
152void ModelBuilderHelper::SetVarUpperBound(int var_index, double ub) {
153 model_.mutable_variable(var_index)->set_upper_bound(ub);
154}
155
156void ModelBuilderHelper::SetVarIntegrality(int var_index, bool is_integer) {
157 model_.mutable_variable(var_index)->set_is_integer(is_integer);
158}
159
161 double coeff) {
162 model_.mutable_variable(var_index)->set_objective_coefficient(coeff);
163}
164
165void ModelBuilderHelper::SetVarName(int var_index, const std::string& name) {
166 model_.mutable_variable(var_index)->set_name(name);
167}
168
169double ModelBuilderHelper::VarLowerBound(int var_index) const {
170 return model_.variable(var_index).lower_bound();
171}
172
173double ModelBuilderHelper::VarUpperBound(int var_index) const {
174 return model_.variable(var_index).upper_bound();
175}
176
177bool ModelBuilderHelper::VarIsIntegral(int var_index) const {
178 return model_.variable(var_index).is_integer();
179}
180
182 return model_.variable(var_index).objective_coefficient();
183}
184
185std::string ModelBuilderHelper::VarName(int var_index) const {
186 return model_.variable(var_index).name();
187}
188
190 const int index = model_.constraint_size();
191 model_.add_constraint();
192 return index;
193}
194
195void ModelBuilderHelper::SetConstraintLowerBound(int ct_index, double lb) {
196 model_.mutable_constraint(ct_index)->set_lower_bound(lb);
197}
198
199void ModelBuilderHelper::SetConstraintUpperBound(int ct_index, double ub) {
200 model_.mutable_constraint(ct_index)->set_upper_bound(ub);
201}
202
204 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
205 ct_proto->clear_var_index();
206 ct_proto->clear_coefficient();
207}
208
209void ModelBuilderHelper::AddConstraintTerm(int ct_index, int var_index,
210 double coeff) {
211 if (coeff == 0.0) return;
212 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
213 ct_proto->add_var_index(var_index);
214 ct_proto->add_coefficient(coeff);
215}
216
217void ModelBuilderHelper::SafeAddConstraintTerm(int ct_index, int var_index,
218 double coeff) {
219 if (coeff == 0.0) return;
220 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
221 for (int i = 0; i < ct_proto->var_index_size(); ++i) {
222 if (ct_proto->var_index(i) == var_index) {
223 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
224 return;
225 }
226 }
227 // If we reach this point, the variable does not exist in the constraint yet,
228 // so we add it to the constraint as a new term.
229 ct_proto->add_var_index(var_index);
230 ct_proto->add_coefficient(coeff);
231}
232
234 const std::string& name) {
235 model_.mutable_constraint(ct_index)->set_name(name);
236}
237
238void ModelBuilderHelper::SetConstraintCoefficient(int ct_index, int var_index,
239 double coeff) {
240 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
241 for (int i = 0; i < ct_proto->var_index_size(); ++i) {
242 if (ct_proto->var_index(i) == var_index) {
243 ct_proto->set_coefficient(i, coeff);
244 return;
245 }
246 }
247 // If we reach this point, the variable does not exist in the constraint yet,
248 // so we add it to the constraint as a newterm.
249 ct_proto->add_var_index(var_index);
250 ct_proto->add_coefficient(coeff);
251}
252
254 return model_.constraint(ct_index).lower_bound();
255}
256
258 return model_.constraint(ct_index).upper_bound();
259}
260
261std::string ModelBuilderHelper::ConstraintName(int ct_index) const {
262 return model_.constraint(ct_index).name();
263}
264
265std::vector<int> ModelBuilderHelper::ConstraintVarIndices(int ct_index) const {
266 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
267 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
268}
269
271 int ct_index) const {
272 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
273 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
274}
275
277 const int index = model_.general_constraint_size();
278 // Create the mew constraint, and force the type to indicator ct.
279 model_.add_general_constraint()->mutable_indicator_constraint();
280 return index;
281}
282
284 const MPGeneralConstraintProto& gen = model_.general_constraint(ct_index);
285 return gen.general_constraint_case() ==
287}
288
290 double lb) {
291 DCHECK(IsEnforcedConstraint(ct_index));
292 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
293 MPConstraintProto* ct_proto =
295 ct_proto->set_lower_bound(lb);
296}
297
299 double ub) {
300 DCHECK(IsEnforcedConstraint(ct_index));
301 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
302 MPConstraintProto* ct_proto =
304 ct_proto->set_upper_bound(ub);
305}
306
308 MPConstraintProto* ct_proto = model_.mutable_general_constraint(ct_index)
309 ->mutable_indicator_constraint()
310 ->mutable_constraint();
311 ct_proto->clear_var_index();
312 ct_proto->clear_coefficient();
313}
314
315void ModelBuilderHelper::AddEnforcedConstraintTerm(int ct_index, int var_index,
316 double coeff) {
317 DCHECK(IsEnforcedConstraint(ct_index));
318 if (coeff == 0.0) return;
319 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
320 MPConstraintProto* ct_proto =
322 ct_proto->add_var_index(var_index);
323 ct_proto->add_coefficient(coeff);
324}
325
327 int var_index,
328 double coeff) {
329 DCHECK(IsEnforcedConstraint(ct_index));
330 if (coeff == 0.0) return;
331 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
332 MPConstraintProto* ct_proto =
334 for (int i = 0; i < ct_proto->var_index_size(); ++i) {
335 if (ct_proto->var_index(i) == var_index) {
336 ct_proto->set_coefficient(i, coeff + ct_proto->coefficient(i));
337 return;
338 }
339 }
340 // If we reach this point, the variable does not exist in the constraint yet,
341 // so we add it to the constraint as a new term.
342 ct_proto->add_var_index(var_index);
343 ct_proto->add_coefficient(coeff);
344}
345
347 const std::string& name) {
348 model_.mutable_general_constraint(ct_index)->set_name(name);
349}
350
352 int var_index,
353 double coeff) {
354 DCHECK(IsEnforcedConstraint(ct_index));
355 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
356 MPConstraintProto* ct_proto =
358 for (int i = 0; i < ct_proto->var_index_size(); ++i) {
359 if (ct_proto->var_index(i) == var_index) {
360 ct_proto->set_coefficient(i, coeff);
361 return;
362 }
363 }
364 // If we reach this point, the variable does not exist in the constraint yet,
365 // so we add it to the constraint as a new term.
366 ct_proto->add_var_index(var_index);
367 ct_proto->add_coefficient(coeff);
368}
369
371 int var_index) {
372 DCHECK(IsEnforcedConstraint(ct_index));
373 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
375}
376
378 bool positive) {
379 DCHECK(IsEnforcedConstraint(ct_index));
380 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
382}
383
385 DCHECK(IsEnforcedConstraint(ct_index));
386 return model_.general_constraint(ct_index)
387 .indicator_constraint()
388 .constraint()
389 .lower_bound();
390}
391
393 DCHECK(IsEnforcedConstraint(ct_index));
394 return model_.general_constraint(ct_index)
395 .indicator_constraint()
396 .constraint()
397 .upper_bound();
398}
399
400std::string ModelBuilderHelper::EnforcedConstraintName(int ct_index) const {
401 DCHECK(IsEnforcedConstraint(ct_index));
402 return model_.general_constraint(ct_index).name();
403}
404
406 int ct_index) const {
407 DCHECK(IsEnforcedConstraint(ct_index));
408 const MPConstraintProto& ct_proto =
409 model_.general_constraint(ct_index).indicator_constraint().constraint();
410 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
411}
412
414 int ct_index) const {
415 DCHECK(IsEnforcedConstraint(ct_index));
416 const MPConstraintProto& ct_proto =
417 model_.general_constraint(ct_index).indicator_constraint().constraint();
418 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
419}
420
422 DCHECK(IsEnforcedConstraint(ct_index));
423 return model_.general_constraint(ct_index).indicator_constraint().var_index();
424}
425
427 DCHECK(IsEnforcedConstraint(ct_index));
428 return model_.general_constraint(ct_index)
429 .indicator_constraint()
430 .var_value() != 0;
431}
432
433int ModelBuilderHelper::num_variables() const { return model_.variable_size(); }
434
436 return model_.constraint_size() + model_.general_constraint_size();
437}
438
439std::string ModelBuilderHelper::name() const { return model_.name(); }
440
441void ModelBuilderHelper::SetName(const std::string& name) {
442 model_.set_name(name);
443}
445 for (MPVariableProto& var : *model_.mutable_variable()) {
446 var.clear_objective_coefficient();
447 }
448}
449
450bool ModelBuilderHelper::maximize() const { return model_.maximize(); }
451
453 model_.set_maximize(maximize);
454}
455
457 return model_.objective_offset();
458}
459
461 model_.set_objective_offset(offset);
462}
463
464void ModelBuilderHelper::ClearHints() { model_.clear_solution_hint(); }
465
466void ModelBuilderHelper::AddHint(int var_index, double var_value) {
467 model_.mutable_solution_hint()->add_var_index(var_index);
468 model_.mutable_solution_hint()->add_var_value(var_value);
469}
470
471std::optional<MPSolutionResponse> ModelSolverHelper::SolveRequest(
472 const MPModelRequest& request) {
475 request.solver_type()))) {
476 return std::nullopt;
477 }
478 return SolveMPModel(request, &interrupter_);
479}
480
481namespace {
482SolveStatus MPSolverResponseStatusToSolveStatus(MPSolverResponseStatus s) {
483 switch (s) {
484 case MPSOLVER_OPTIMAL:
512 default:
514 }
515}
516} // namespace
517
518ModelSolverHelper::ModelSolverHelper(const std::string& solver_name)
519 : evaluator_(this) {
520 if (solver_name.empty()) return;
522 if (!MPSolver::ParseSolverType(solver_name, &parsed_type)) {
523 VLOG(1) << "Unsupported type " << solver_name;
524 } else {
525 solver_type_ = static_cast<MPModelRequest::SolverType>(parsed_type);
526 }
527}
528
530 if (!solver_type_.has_value()) return false;
531 if (solver_type_.value() == MPModelRequest::GLOP_LINEAR_PROGRAMMING) {
532 return true;
533 }
534#ifdef USE_PDLP
535 if (solver_type_.value() == MPModelRequest::PDLP_LINEAR_PROGRAMMING) {
536 return true;
537 }
538#endif // USE_PDLP
539 if (solver_type_.value() == MPModelRequest::SAT_INTEGER_PROGRAMMING) {
540 return true;
541 }
542#ifdef USE_SCIP
543 if (solver_type_.value() == MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING) {
544 return true;
545 }
546#endif // USE_SCIP
547#ifdef USE_HIGHS
548 if (solver_type_.value() == MPModelRequest::HIGHS_LINEAR_PROGRAMMING ||
549 solver_type_.value() == MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING) {
550 return true;
551 }
552#endif // USE_HIGHS
553 if (solver_type_.value() ==
555 solver_type_.value() == MPModelRequest::GUROBI_LINEAR_PROGRAMMING) {
557 }
558 return false;
559}
560
562 response_.reset();
563 if (!solver_type_.has_value()) {
564 response_->set_status(
566 return;
567 }
568
569 MPModelRequest request;
570 *request.mutable_model() = model.model();
571 request.set_solver_type(solver_type_.value());
572 request.set_enable_internal_solver_output(solver_output_);
573 if (time_limit_in_second_.has_value()) {
574 request.set_solver_time_limit_seconds(time_limit_in_second_.value());
575 }
576 if (!solver_specific_parameters_.empty()) {
577 request.set_solver_specific_parameters(solver_specific_parameters_);
578 }
579 switch (solver_type_.value()) {
581 response_ =
582 GlopSolveProto(std::move(request), &interrupt_solve_, log_callback_);
583 break;
584 }
586 response_ = SatSolveProto(std::move(request), &interrupt_solve_,
587 log_callback_, nullptr);
588 break;
589 }
590#if defined(USE_SCIP)
592 // TODO(user): Enable log_callback support.
593 // TODO(user): Enable interrupt_solve.
594 const auto temp = ScipSolveProto(std::move(request));
595 if (temp.ok()) {
596 response_ = std::move(temp.value());
597 }
598 break;
599 }
600#endif // defined(USE_SCIP)
601#if defined(USE_PDLP)
603 const auto temp = PdlpSolveProto(std::move(request));
604 if (temp.ok()) {
605 response_ = std::move(temp.value());
606 }
607 break;
608 }
609#endif // defined(USE_PDLP)
610 case MPModelRequest::
611 GUROBI_LINEAR_PROGRAMMING: // ABSL_FALLTHROUGH_INTENDED
613 const auto temp = GurobiSolveProto(std::move(request));
614 if (temp.ok()) {
615 response_ = std::move(temp.value());
616 }
617 break;
618 }
619#if defined(USE_HIGHS)
620 case MPModelRequest::HIGHS_LINEAR_PROGRAMMING: // ABSL_FALLTHROUGH_INTENDED
622 // TODO(user): Enable log_callback support.
623 // TODO(user): Enable interrupt_solve.
624 const auto temp = HighsSolveProto(std::move(request));
625 if (temp.ok()) {
626 response_ = std::move(temp.value());
627 }
628 break;
629 }
630#endif // defined(USE_HIGHS)
631 default: {
632 response_->set_status(
634 }
635 }
636 if (response_->status() == MPSOLVER_OPTIMAL ||
637 response_->status() == MPSOLVER_FEASIBLE) {
638 model_of_last_solve_ = &model.model();
639 activities_.assign(model.num_constraints(),
640 std::numeric_limits<double>::quiet_NaN());
641 } else {
642 activities_.clear();
643 }
644}
645
647 std::function<void(const std::string&)> log_callback) {
648 log_callback_ = std::move(log_callback);
649}
650
652 MbLogCallback* log_callback) {
653 log_callback_ = [log_callback](const std::string& message) {
654 log_callback->NewMessage(message);
655 };
656}
657
658void ModelSolverHelper::ClearLogCallback() { log_callback_ = nullptr; }
659
661 interrupter_.Interrupt();
662 interrupt_solve_ = true;
663 return true;
664}
665
666bool ModelSolverHelper::has_response() const { return response_.has_value(); }
667
669 return response_.has_value() &&
670 (response_.value().status() ==
672 response_.value().status() ==
674}
675
677 return response_.value();
678}
679
681 if (!response_.has_value()) {
683 }
684 return MPSolverResponseStatusToSolveStatus(response_.value().status());
685}
686
688 if (!has_response()) return 0.0;
689 return response_.value().objective_value();
690}
691
693 if (!has_response()) return 0.0;
694 return response_.value().best_objective_bound();
695}
696
697double ModelSolverHelper::variable_value(int var_index) const {
698 if (!has_response()) return 0.0;
699 if (var_index >= response_.value().variable_value_size()) return 0.0;
700 return response_.value().variable_value(var_index);
701}
702
704 std::shared_ptr<LinearExpr> expr) const {
705 if (!has_response()) return 0.0;
706 evaluator_.Clear();
707 evaluator_.AddToProcess(expr, 1.0);
708 return evaluator_.Evaluate();
709}
710
711double ModelSolverHelper::reduced_cost(int var_index) const {
712 if (!has_response()) return 0.0;
713 if (var_index >= response_.value().reduced_cost_size()) return 0.0;
714 return response_.value().reduced_cost(var_index);
715}
716
717double ModelSolverHelper::dual_value(int ct_index) const {
718 if (!has_response()) return 0.0;
719 if (ct_index >= response_.value().dual_value_size()) return 0.0;
720 return response_.value().dual_value(ct_index);
721}
722
723double ModelSolverHelper::activity(int ct_index) {
724 if (!has_response() || ct_index >= activities_.size() ||
725 !model_of_last_solve_.has_value()) {
726 return 0.0;
727 }
728
729 if (std::isnan(activities_[ct_index])) {
730 const MPConstraintProto& ct_proto =
731 model_of_last_solve_.value()->constraint(ct_index);
732 double result = 0.0;
733 for (int i = 0; i < ct_proto.var_index_size(); ++i) {
734 result += response_->variable_value(ct_proto.var_index(i)) *
735 ct_proto.coefficient(i);
736 }
737 activities_[ct_index] = result;
738 }
739 return activities_[ct_index];
740}
741
743 if (!has_response()) return "";
744 return response_.value().status_str();
745}
746
748 if (!response_.has_value()) return 0.0;
749 if (!response_.value().has_solve_info()) return 0.0;
750 return response_.value().solve_info().solve_wall_time_seconds();
751}
752
754 if (!response_.has_value()) return 0.0;
755 if (!response_.value().has_solve_info()) return 0.0;
756 return response_.value().solve_info().solve_user_time_seconds();
757}
758
760 time_limit_in_second_ = limit;
761}
762
764 const std::string& solver_specific_parameters) {
765 solver_specific_parameters_ = solver_specific_parameters;
766}
767
768void ModelSolverHelper::EnableOutput(bool enabled) { solver_output_ = enabled; }
769
770// Expressions.
771std::shared_ptr<LinearExpr> LinearExpr::Term(std::shared_ptr<LinearExpr> expr,
772 double coeff) {
773 return std::make_shared<AffineExpr>(expr, coeff, 0.0);
774}
775
776std::shared_ptr<LinearExpr> LinearExpr::Affine(std::shared_ptr<LinearExpr> expr,
777 double coeff, double constant) {
778 if (coeff == 1.0 && constant == 0.0) return expr;
779 return std::make_shared<AffineExpr>(expr, coeff, constant);
780}
781
782std::shared_ptr<LinearExpr> LinearExpr::AffineCst(double value, double coeff,
783 double constant) {
784 return std::make_shared<FixedValue>(value * coeff + constant);
785}
786
787std::shared_ptr<LinearExpr> LinearExpr::Constant(double value) {
788 return std::make_shared<FixedValue>(value);
789}
790
791std::shared_ptr<LinearExpr> LinearExpr::Add(std::shared_ptr<LinearExpr> expr) {
792 std::vector<std::shared_ptr<LinearExpr>> exprs;
793 exprs.push_back(shared_from_this());
794 exprs.push_back(expr);
795 return std::make_shared<SumArray>(exprs, 0.0);
796}
797
798std::shared_ptr<LinearExpr> LinearExpr::AddFloat(double cst) {
799 if (cst == 0.0) return shared_from_this();
800 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, cst);
801}
802
803std::shared_ptr<LinearExpr> LinearExpr::Sub(std::shared_ptr<LinearExpr> expr) {
804 std::vector<std::shared_ptr<LinearExpr>> exprs;
805 exprs.push_back(shared_from_this());
806 exprs.push_back(expr->MulFloat(-1.0));
807 return std::make_shared<SumArray>(exprs, 0.0);
808}
809
810std::shared_ptr<LinearExpr> LinearExpr::SubFloat(double cst) {
811 if (cst == 0.0) return shared_from_this();
812 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, -cst);
813}
814
815std::shared_ptr<LinearExpr> LinearExpr::RSubFloat(double cst) {
816 return std::make_shared<AffineExpr>(shared_from_this(), -1.0, cst);
817}
818
819std::shared_ptr<LinearExpr> LinearExpr::MulFloat(double cst) {
820 if (cst == 0.0) return std::make_shared<FixedValue>(0.0);
821 if (cst == 1.0) return shared_from_this();
822 return std::make_shared<AffineExpr>(shared_from_this(), cst, 0.0);
823}
824
825std::shared_ptr<LinearExpr> LinearExpr::Neg() {
826 return std::make_shared<AffineExpr>(shared_from_this(), -1, 0);
827}
828
829// Expression visitors.
830
831void ExprVisitor::AddToProcess(std::shared_ptr<LinearExpr> expr, double coeff) {
832 to_process_.push_back(std::make_pair(expr, coeff));
833}
834
835void ExprVisitor::AddConstant(double constant) { offset_ += constant; }
836
838 to_process_.clear();
839 offset_ = 0.0;
840}
841
842void ExprFlattener::AddVarCoeff(std::shared_ptr<Variable> var, double coeff) {
843 canonical_terms_[var] += coeff;
844}
845
846double ExprFlattener::Flatten(std::vector<std::shared_ptr<Variable>>* vars,
847 std::vector<double>* coeffs) {
848 while (!to_process_.empty()) {
849 const auto [expr, coeff] = to_process_.back();
850 to_process_.pop_back();
851 expr->Visit(*this, coeff);
852 }
853
854 vars->clear();
855 coeffs->clear();
856 for (const auto& [var, coeff] : canonical_terms_) {
857 if (coeff == 0.0) continue;
858 vars->push_back(var);
859 coeffs->push_back(coeff);
860 }
861
862 return offset_;
863}
864
865void ExprEvaluator::AddVarCoeff(std::shared_ptr<Variable> var, double coeff) {
866 offset_ += coeff * helper_->variable_value(var->index());
867}
868
870 offset_ = 0.0;
871 while (!to_process_.empty()) {
872 const auto [expr, coeff] = to_process_.back();
873 to_process_.pop_back();
874 expr->Visit(*this, coeff);
875 }
876 return offset_;
877}
878
879FlatExpr::FlatExpr(std::shared_ptr<LinearExpr> expr) {
880 ExprFlattener lin;
881 lin.AddToProcess(expr, 1.0);
882 offset_ = lin.Flatten(&vars_, &coeffs_);
883}
884
885FlatExpr::FlatExpr(std::shared_ptr<LinearExpr> pos,
886 std::shared_ptr<LinearExpr> neg) {
887 ExprFlattener lin;
888 lin.AddToProcess(pos, 1.0);
889 lin.AddToProcess(neg, -1.0);
890 offset_ = lin.Flatten(&vars_, &coeffs_);
891}
892
893FlatExpr::FlatExpr(const std::vector<std::shared_ptr<Variable>>& vars,
894 const std::vector<double>& coeffs, double offset)
895 : vars_(vars), coeffs_(coeffs), offset_(offset) {}
896
897FlatExpr::FlatExpr(double offset) : offset_(offset) {}
898
899std::vector<int> FlatExpr::VarIndices() const {
900 std::vector<int> var_indices;
901 var_indices.reserve(vars_.size());
902 for (const std::shared_ptr<Variable>& var : vars_) {
903 var_indices.push_back(var->index());
904 }
905 return var_indices;
906}
907
908void FlatExpr::Visit(ExprVisitor& lin, double c) {
909 for (int i = 0; i < vars_.size(); ++i) {
910 lin.AddVarCoeff(vars_[i], coeffs_[i] * c);
911 }
912 lin.AddConstant(offset_ * c);
913}
914
915std::string FlatExpr::ToString() const {
916 if (vars_.empty()) {
917 return absl::StrCat(offset_);
918 }
919 std::string s;
920 int num_printed = 0;
921 for (int i = 0; i < vars_.size(); ++i) {
922 DCHECK_NE(coeffs_[i], 0.0);
923 ++num_printed;
924 if (num_printed > 5) {
925 absl::StrAppend(&s, " + ...");
926 break;
927 }
928 if (num_printed == 1) {
929 if (coeffs_[i] == 1.0) {
930 absl::StrAppend(&s, vars_[i]->ToString());
931 } else if (coeffs_[i] == -1.0) {
932 absl::StrAppend(&s, "-", vars_[i]->ToString());
933 } else {
934 absl::StrAppend(&s, coeffs_[i], " * ", vars_[i]->ToString());
935 }
936 } else {
937 if (coeffs_[i] == 1.0) {
938 absl::StrAppend(&s, " + ", vars_[i]->ToString());
939 } else if (coeffs_[i] == -1.0) {
940 absl::StrAppend(&s, " - ", vars_[i]->ToString());
941 } else if (coeffs_[i] > 0.0) {
942 absl::StrAppend(&s, " + ", coeffs_[i], " * ", vars_[i]->ToString());
943 } else {
944 absl::StrAppend(&s, " - ", -coeffs_[i], " * ", vars_[i]->ToString());
945 }
946 }
947 }
948 // If there are no terms, just print the offset.
949 if (num_printed == 0) {
950 return absl::StrCat(offset_);
951 }
952
953 // If there is an offset, print it.
954 if (offset_ != 0.0) {
955 if (offset_ > 0.0) {
956 absl::StrAppend(&s, " + ", offset_);
957 } else {
958 absl::StrAppend(&s, " - ", -offset_);
959 }
960 }
961 return s;
962}
963
964std::string FlatExpr::DebugString() const {
965 std::string s = absl::StrCat(
966 "FlatExpr(",
967 absl::StrJoin(vars_, ", ",
968 [](std::string* out, std::shared_ptr<Variable> expr) {
969 absl::StrAppend(out, expr->DebugString());
970 }));
971 if (offset_ != 0.0) {
972 absl::StrAppend(&s, ", offset=", offset_);
973 }
974 absl::StrAppend(&s, ")");
975 return s;
976}
977
978SumArray::SumArray(std::vector<std::shared_ptr<LinearExpr>> exprs,
979 double offset)
980 : exprs_(std::move(exprs)), offset_(offset) {}
981
982void SumArray::Visit(ExprVisitor& lin, double c) {
983 for (int i = 0; i < exprs_.size(); ++i) {
984 lin.AddToProcess(exprs_[i], c);
985 }
986 if (offset_ != 0.0) {
987 lin.AddConstant(offset_ * c);
988 }
989}
990
991std::string SumArray::ToString() const {
992 if (exprs_.empty()) {
993 if (offset_ != 0.0) {
994 return absl::StrCat(offset_);
995 }
996 }
997 std::string s = "(";
998 for (int i = 0; i < exprs_.size(); ++i) {
999 if (i > 0) {
1000 absl::StrAppend(&s, " + ");
1001 }
1002 absl::StrAppend(&s, exprs_[i]->ToString());
1003 }
1004 if (offset_ != 0.0) {
1005 if (offset_ > 0.0) {
1006 absl::StrAppend(&s, " + ", offset_);
1007 } else {
1008 absl::StrAppend(&s, " - ", -offset_);
1009 }
1010 }
1011 absl::StrAppend(&s, ")");
1012 return s;
1013}
1014
1015std::string SumArray::DebugString() const {
1016 std::string s = absl::StrCat(
1017 "SumArray(",
1018 absl::StrJoin(exprs_, ", ",
1019 [](std::string* out, std::shared_ptr<LinearExpr> expr) {
1020 absl::StrAppend(out, expr->DebugString());
1021 }));
1022 if (offset_ != 0.0) {
1023 absl::StrAppend(&s, ", offset=", offset_);
1024 }
1025 absl::StrAppend(&s, ")");
1026 return s;
1027}
1028
1029std::shared_ptr<LinearExpr> SumArray::AddInPlace(
1030 std::shared_ptr<LinearExpr> expr) {
1031 exprs_.push_back(std::move(expr));
1032 return shared_from_this();
1033}
1034
1035std::shared_ptr<LinearExpr> SumArray::AddFloatInPlace(double cst) {
1036 offset_ += cst;
1037 return shared_from_this();
1038}
1039
1040int SumArray::num_exprs() const { return exprs_.size(); }
1041
1042double SumArray::offset() const { return offset_; }
1043
1044void FixedValue::Visit(ExprVisitor& lin, double c) {
1045 lin.AddConstant(value_ * c);
1046}
1047
1048std::string FixedValue::ToString() const { return absl::StrCat(value_); }
1049
1050std::string FixedValue::DebugString() const {
1051 return absl::StrCat("FixedValue(", value_, ")");
1052}
1053
1055 const std::vector<std::shared_ptr<LinearExpr>>& exprs,
1056 const std::vector<double>& coeffs, double offset)
1057 : exprs_(exprs.begin(), exprs.end()),
1058 coeffs_(coeffs.begin(), coeffs.end()),
1059 offset_(offset) {}
1060
1062 for (int i = 0; i < exprs_.size(); ++i) {
1063 lin.AddToProcess(exprs_[i], coeffs_[i] * c);
1064 }
1065 lin.AddConstant(offset_ * c);
1066}
1067
1068std::string WeightedSumArray::ToString() const {
1069 if (exprs_.empty()) {
1070 return absl::StrCat(offset_);
1071 }
1072 std::string s = "(";
1073 bool first_printed = true;
1074 for (int i = 0; i < exprs_.size(); ++i) {
1075 if (coeffs_[i] == 0.0) continue;
1076 if (first_printed) {
1077 first_printed = false;
1078 if (coeffs_[i] == 1.0) {
1079 absl::StrAppend(&s, exprs_[i]->ToString());
1080 } else if (coeffs_[i] == -1.0) {
1081 absl::StrAppend(&s, "-", exprs_[i]->ToString());
1082 } else {
1083 absl::StrAppend(&s, coeffs_[i], " * ", exprs_[i]->ToString());
1084 }
1085 } else {
1086 if (coeffs_[i] == 1.0) {
1087 absl::StrAppend(&s, " + ", exprs_[i]->ToString());
1088 } else if (coeffs_[i] == -1.0) {
1089 absl::StrAppend(&s, " - ", exprs_[i]->ToString());
1090 } else if (coeffs_[i] > 0.0) {
1091 absl::StrAppend(&s, " + ", coeffs_[i], " * ", exprs_[i]->ToString());
1092 } else {
1093 absl::StrAppend(&s, " - ", -coeffs_[i], " * ", exprs_[i]->ToString());
1094 }
1095 }
1096 }
1097 // If there are no terms, just print the offset.
1098 if (first_printed) {
1099 return absl::StrCat(offset_);
1100 }
1101
1102 // If there is an offset, print it.
1103 if (offset_ != 0.0) {
1104 if (offset_ > 0.0) {
1105 absl::StrAppend(&s, " + ", offset_);
1106 } else {
1107 absl::StrAppend(&s, " - ", -offset_);
1108 }
1109 }
1110 absl::StrAppend(&s, ")");
1111 return s;
1112}
1113
1115 return absl::StrCat(
1116 "WeightedSumArray([",
1117 absl::StrJoin(exprs_, ", ",
1118 [](std::string* out, std::shared_ptr<LinearExpr> e) {
1119 absl::StrAppend(out, e->DebugString());
1120 }),
1121 "], [", absl::StrJoin(coeffs_, "], "), offset_, ")");
1122}
1123
1124AffineExpr::AffineExpr(std::shared_ptr<LinearExpr> expr, double coeff,
1125 double offset)
1126 : expr_(expr), coeff_(coeff), offset_(offset) {}
1127
1128void AffineExpr::Visit(ExprVisitor& lin, double c) {
1129 lin.AddToProcess(expr_, c * coeff_);
1130 lin.AddConstant(offset_ * c);
1131}
1132
1133std::shared_ptr<LinearExpr> AffineExpr::AddFloat(double cst) {
1134 if (cst == 0.0) return shared_from_this();
1135 return LinearExpr::Affine(expr_, coeff_, offset_ + cst);
1136}
1137
1138std::shared_ptr<LinearExpr> AffineExpr::SubFloat(double cst) {
1139 if (cst == 0.0) return shared_from_this();
1140 return LinearExpr::Affine(expr_, coeff_, offset_ - cst);
1141}
1142
1143std::shared_ptr<LinearExpr> AffineExpr::RSubFloat(double cst) {
1144 return LinearExpr::Affine(expr_, -coeff_, cst - offset_);
1145}
1146
1147std::shared_ptr<LinearExpr> AffineExpr::MulFloat(double cst) {
1148 if (cst == 0.0) return std::make_shared<FixedValue>(0);
1149 if (cst == 1.0) return shared_from_this();
1150 return LinearExpr::Affine(expr_, coeff_ * cst, offset_ * cst);
1151}
1152
1153std::shared_ptr<LinearExpr> AffineExpr::Neg() {
1154 return LinearExpr::Affine(expr_, -coeff_, -offset_);
1155}
1156
1157std::string AffineExpr::ToString() const {
1158 std::string s = "(";
1159 if (coeff_ == 1.0) {
1160 absl::StrAppend(&s, expr_->ToString());
1161 } else if (coeff_ == -1.0) {
1162 absl::StrAppend(&s, "-", expr_->ToString());
1163 } else {
1164 absl::StrAppend(&s, coeff_, " * ", expr_->ToString());
1165 }
1166 if (offset_ > 0.0) {
1167 absl::StrAppend(&s, " + ", offset_);
1168 } else if (offset_ < 0.0) {
1169 absl::StrAppend(&s, " - ", -offset_);
1170 }
1171 absl::StrAppend(&s, ")");
1172 return s;
1173}
1174
1175std::string AffineExpr::DebugString() const {
1176 return absl::StrCat("AffineExpr(expr=", expr_->DebugString(),
1177 ", coeff=", coeff_, ", offset=", offset_, ")");
1178}
1179std::shared_ptr<BoundedLinearExpression> LinearExpr::Eq(
1180 std::shared_ptr<LinearExpr> rhs) {
1181 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs, 0.0,
1182 0.0);
1183}
1184
1185std::shared_ptr<BoundedLinearExpression> LinearExpr::EqCst(double rhs) {
1186 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs,
1187 rhs);
1188}
1189
1190std::shared_ptr<BoundedLinearExpression> LinearExpr::Le(
1191 std::shared_ptr<LinearExpr> rhs) {
1192 return std::make_shared<BoundedLinearExpression>(
1193 shared_from_this(), rhs, -std::numeric_limits<double>::infinity(), 0.0);
1194}
1195
1196std::shared_ptr<BoundedLinearExpression> LinearExpr::LeCst(double rhs) {
1197 return std::make_shared<BoundedLinearExpression>(
1198 shared_from_this(), -std::numeric_limits<double>::infinity(), rhs);
1199}
1200
1201std::shared_ptr<BoundedLinearExpression> LinearExpr::Ge(
1202 std::shared_ptr<LinearExpr> rhs) {
1203 return std::make_shared<BoundedLinearExpression>(
1204 shared_from_this(), rhs, 0.0, std::numeric_limits<double>::infinity());
1205}
1206
1207std::shared_ptr<BoundedLinearExpression> LinearExpr::GeCst(double rhs) {
1208 return std::make_shared<BoundedLinearExpression>(
1209 shared_from_this(), rhs, std::numeric_limits<double>::infinity());
1210}
1211
1212bool VariableComparator::operator()(std::shared_ptr<Variable> lhs,
1213 std::shared_ptr<Variable> rhs) const {
1214 return lhs->index() < rhs->index();
1215}
1216
1219
1221 bool is_integral)
1222 : helper_(helper) {
1223 index_ = helper_->AddVar();
1224 helper_->SetVarLowerBound(index_, lb);
1225 helper_->SetVarUpperBound(index_, ub);
1226 helper_->SetVarIntegrality(index_, is_integral);
1227}
1228
1230 bool is_integral, const std::string& name)
1231 : helper_(helper) {
1232 index_ = helper_->AddVar();
1233 helper_->SetVarLowerBound(index_, lb);
1234 helper_->SetVarUpperBound(index_, ub);
1235 helper_->SetVarIntegrality(index_, is_integral);
1236 helper_->SetVarName(index_, name);
1237}
1238
1240 bool is_integral)
1241 : helper_(helper) {
1242 index_ = helper_->AddVar();
1243 helper_->SetVarLowerBound(index_, lb);
1244 helper_->SetVarUpperBound(index_, ub);
1245 helper_->SetVarIntegrality(index_, is_integral);
1246}
1247
1249 bool is_integral, const std::string& name)
1250 : helper_(helper) {
1251 index_ = helper_->AddVar();
1252 helper_->SetVarLowerBound(index_, lb);
1253 helper_->SetVarUpperBound(index_, ub);
1254 helper_->SetVarIntegrality(index_, is_integral);
1255 helper_->SetVarName(index_, name);
1256}
1257
1258std::string Variable::ToString() const {
1259 if (!helper_->VarName(index_).empty()) {
1260 return helper_->VarName(index_);
1261 } else {
1262 return absl::StrCat("Variable(", index_, ")");
1263 }
1264}
1265
1266std::string Variable::DebugString() const {
1267 return absl::StrCat("Variable(index=", index_,
1268 ", lb=", helper_->VarLowerBound(index_),
1269 ", ub=", helper_->VarUpperBound(index_),
1270 ", is_integral=", helper_->VarIsIntegral(index_),
1271 ", name=\'", helper_->VarName(index_), "')");
1272}
1273
1274std::string Variable::name() const {
1275 const std::string& var_name = helper_->VarName(index_);
1276 if (!var_name.empty()) return var_name;
1277 return absl::StrCat("variable#", index_);
1278}
1279
1280void Variable::SetName(const std::string& name) {
1281 helper_->SetVarName(index_, name);
1282}
1283
1284double Variable::lower_bounds() const { return helper_->VarLowerBound(index_); }
1285
1287 helper_->SetVarLowerBound(index_, lb);
1288}
1289
1290double Variable::upper_bound() const { return helper_->VarUpperBound(index_); }
1291
1293 helper_->SetVarUpperBound(index_, ub);
1294}
1295
1296bool Variable::is_integral() const { return helper_->VarIsIntegral(index_); }
1297
1299 helper_->SetVarIntegrality(index_, is_integral);
1300}
1301
1303 return helper_->VarObjectiveCoefficient(index_);
1304}
1305
1307 helper_->SetVarObjectiveCoefficient(index_, coeff);
1308}
1309
1311 std::shared_ptr<LinearExpr> expr, double lower_bound, double upper_bound) {
1312 FlatExpr flat_expr(expr);
1313 vars_ = flat_expr.vars();
1314 coeffs_ = flat_expr.coeffs();
1315 lower_bound_ = lower_bound - flat_expr.offset();
1316 upper_bound_ = upper_bound - flat_expr.offset();
1317}
1318
1320 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1321 double lower_bound, double upper_bound) {
1322 FlatExpr flat_expr(pos, neg);
1323 vars_ = flat_expr.vars();
1324 coeffs_ = flat_expr.coeffs();
1325 lower_bound_ = lower_bound - flat_expr.offset();
1326 upper_bound_ = upper_bound - flat_expr.offset();
1327}
1328
1330 std::shared_ptr<LinearExpr> expr, int64_t lower_bound,
1331 int64_t upper_bound) {
1332 FlatExpr flat_expr(expr);
1333 vars_ = flat_expr.vars();
1334 coeffs_ = flat_expr.coeffs();
1335 lower_bound_ = lower_bound - flat_expr.offset();
1336 upper_bound_ = upper_bound - flat_expr.offset();
1337}
1338
1340 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1341 int64_t lower_bound, int64_t upper_bound) {
1342 FlatExpr flat_expr(pos, neg);
1343 vars_ = flat_expr.vars();
1344 coeffs_ = flat_expr.coeffs();
1345 lower_bound_ = lower_bound - flat_expr.offset();
1346 upper_bound_ = upper_bound - flat_expr.offset();
1347}
1348
1349double BoundedLinearExpression::lower_bound() const { return lower_bound_; }
1350double BoundedLinearExpression::upper_bound() const { return upper_bound_; }
1351const std::vector<std::shared_ptr<Variable>>& BoundedLinearExpression::vars()
1352 const {
1353 return vars_;
1354}
1355const std::vector<double>& BoundedLinearExpression::coeffs() const {
1356 return coeffs_;
1357}
1359 std::string s;
1360 if (vars_.empty()) {
1361 s = absl::StrCat(0.0);
1362 } else if (vars_.size() == 1) {
1363 const std::string var_name = vars_[0]->ToString();
1364 if (coeffs_[0] == 1) {
1365 s = var_name;
1366 } else if (coeffs_[0] == -1) {
1367 s = absl::StrCat("-", var_name);
1368 } else {
1369 s = absl::StrCat(coeffs_[0], " * ", var_name);
1370 }
1371 } else {
1372 s = "(";
1373 for (int i = 0; i < vars_.size(); ++i) {
1374 const std::string var_name = vars_[i]->ToString();
1375 if (i == 0) {
1376 if (coeffs_[i] == 1) {
1377 absl::StrAppend(&s, var_name);
1378 } else if (coeffs_[i] == -1) {
1379 absl::StrAppend(&s, "-", var_name);
1380 } else {
1381 absl::StrAppend(&s, coeffs_[i], " * ", var_name);
1382 }
1383 } else {
1384 if (coeffs_[i] == 1) {
1385 absl::StrAppend(&s, " + ", var_name);
1386 } else if (coeffs_[i] == -1) {
1387 absl::StrAppend(&s, " - ", var_name);
1388 } else if (coeffs_[i] > 1) {
1389 absl::StrAppend(&s, " + ", coeffs_[i], " * ", var_name);
1390 } else {
1391 absl::StrAppend(&s, " - ", -coeffs_[i], " * ", var_name);
1392 }
1393 }
1394 }
1395 absl::StrAppend(&s, ")");
1396 }
1397 if (lower_bound_ == upper_bound_) {
1398 return absl::StrCat(s, " == ", lower_bound_);
1399 } else if (lower_bound_ == -std::numeric_limits<double>::infinity()) {
1400 if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1401 return absl::StrCat("-inf <= ", s, " <= inf");
1402 } else {
1403 return absl::StrCat(s, " <= ", upper_bound_);
1404 }
1405 } else if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1406 return absl::StrCat(s, " >= ", lower_bound_);
1407 } else {
1408 return absl::StrCat(lower_bound_, " <= ", s, " <= ", upper_bound_);
1409 }
1410}
1411
1413 return absl::StrCat(
1414 "BoundedLinearExpression(vars=[",
1415 absl::StrJoin(vars_, ", ",
1416 [](std::string* out, std::shared_ptr<Variable> var) {
1417 absl::StrAppend(out, var->DebugString());
1418 }),
1419 "], coeffs=[", absl::StrJoin(coeffs_, ", "),
1420 "], lower_bound=", lower_bound_, ", upper_bound=", upper_bound_, ")");
1421}
1422
1423bool BoundedLinearExpression::CastToBool(bool* result) const {
1424 const bool is_zero = lower_bound_ == 0.0 && upper_bound_ == 0.0;
1425 if (is_zero) {
1426 if (vars_.empty()) {
1427 *result = true;
1428 return true;
1429 } else if (vars_.size() == 2 && coeffs_[0] + coeffs_[1] == 0 &&
1430 std::abs(coeffs_[0]) == 1) {
1431 *result = false;
1432 return true;
1433 }
1434 }
1435 return false;
1436}
1437
1438} // namespace mb
1439} // namespace operations_research
void set_coefficient(int index, double value)
GeneralConstraintCase general_constraint_case() const
::operations_research::MPIndicatorConstraint *PROTOBUF_NONNULL mutable_indicator_constraint()
::operations_research::MPConstraintProto *PROTOBUF_NONNULL mutable_constraint()
MPModelRequest_SolverType SolverType
void set_solver_specific_parameters(Arg_ &&arg, Args_... args)
static constexpr SolverType HIGHS_LINEAR_PROGRAMMING
static constexpr SolverType SAT_INTEGER_PROGRAMMING
static constexpr SolverType HIGHS_MIXED_INTEGER_PROGRAMMING
static constexpr SolverType GUROBI_MIXED_INTEGER_PROGRAMMING
::operations_research::MPModelProto *PROTOBUF_NONNULL mutable_model()
static constexpr SolverType PDLP_LINEAR_PROGRAMMING
void set_solver_type(::operations_research::MPModelRequest_SolverType value)
::operations_research::MPModelRequest_SolverType solver_type() const
static constexpr SolverType GUROBI_LINEAR_PROGRAMMING
const ::operations_research::MPModelProto & model() const
static constexpr SolverType GLOP_LINEAR_PROGRAMMING
static constexpr SolverType SCIP_MIXED_INTEGER_PROGRAMMING
static bool SupportsProblemType(OptimizationProblemType problem_type)
static bool ParseSolverType(absl::string_view solver_id, OptimizationProblemType *type)
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
BoundedLinearExpression(std::shared_ptr< LinearExpr > expr, double lower_bound, double upper_bound)
const std::vector< std::shared_ptr< Variable > > & vars() 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
std::vector< std::pair< std::shared_ptr< LinearExpr >, double > > to_process_
void AddToProcess(std::shared_ptr< LinearExpr > expr, double coeff)
virtual void AddVarCoeff(std::shared_ptr< Variable > var, double coeff)=0
void Visit(ExprVisitor &lin, double c) override
std::string DebugString() const override
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)
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)
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 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)
void AddConstraintTerm(int ct_index, int var_index, double coeff)
bool WriteToMpsFile(const std::string &filename, const operations_research::MPModelExportOptions &options=MPModelExportOptions())
bool ReadModelFromProtoFile(const std::string &filename)
std::string ExportToMpsString(const operations_research::MPModelExportOptions &options=MPModelExportOptions())
void SetEnforcedConstraintCoefficient(int ct_index, int var_index, double coeff)
std::string EnforcedConstraintName(int ct_index) const
void AddEnforcedConstraintTerm(int ct_index, int var_index, double coeff)
void OverwriteModel(const ModelBuilderHelper &other_helper)
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)
void AddHint(int var_index, double var_value)
void SetVarObjectiveCoefficient(int var_index, double coeff)
void SetConstraintName(int ct_index, const std::string &name)
bool ImportFromMpsString(const std::string &mps_string)
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
void SafeAddConstraintTerm(int ct_index, int var_index, double coeff)
void SetConstraintCoefficient(int ct_index, int var_index, double coeff)
std::string ExportToLpString(const operations_research::MPModelExportOptions &options=MPModelExportOptions())
std::vector< int > EnforcedConstraintVarIndices(int ct_index) const
void Solve(const ModelBuilderHelper &model)
void SetSolverSpecificParameters(const std::string &solver_specific_parameters)
ModelSolverHelper(const std::string &solver_name)
std::optional< MPSolutionResponse > SolveRequest(const MPModelRequest &request)
const MPSolutionResponse & response() const
void SetLogCallbackFromDirectorClass(MbLogCallback *log_callback)
double expression_value(std::shared_ptr< LinearExpr > expr) const
void SetLogCallback(std::function< void(const std::string &)> log_callback)
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 SetName(const std::string &name)
ModelBuilderHelper * helper() const
std::string DebugString() const override
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
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
Definition file.cc:349
absl::Status SetBinaryProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
Definition file.cc:476
absl::Status SetTextProto(absl::string_view file_name, const google::protobuf::Message &proto, Options options)
Definition file.cc:448
absl::Status GetTextProto(absl::string_view file_name, google::protobuf::Message *proto, Options options)
Definition file.cc:409
absl::Status GetBinaryProto(const absl::string_view file_name, google::protobuf::Message *proto, Options options)
Definition file.cc:463
Options Defaults()
Definition file.h:86
absl::StatusOr< MPModelProto > MpsFileToMPModelProto(absl::string_view mps_file)
absl::StatusOr< MPModelProto > MpsDataToMPModelProto(absl::string_view mps_data)
OR-Tools root namespace.
absl::Status WriteModelToMpsFile(absl::string_view filename, const MPModelProto &model, const MPModelExportOptions &options)
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, std::function< void(const double)> best_bound_callback)
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 > HighsSolveProto(LazyMutableCopy< MPModelRequest > request, HighsSolveInfo *solve_info)
absl::StatusOr< MPSolutionResponse > ScipSolveProto(LazyMutableCopy< MPModelRequest > request)
MPSolutionResponse SolveMPModel(LazyMutableCopy< MPModelRequest > request, const SolveInterrupter *absl_nullable interrupter)
ClosedInterval::Iterator end(ClosedInterval interval)
MPSolutionResponse GlopSolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt_solve, std::function< void(const std::string &)> logging_callback)
absl::StatusOr< MPSolutionResponse > GurobiSolveProto(LazyMutableCopy< MPModelRequest > request, GRBenv *gurobi_env)
absl::StatusOr< std::string > ExportModelAsMpsFormat(const MPModelProto &model, const MPModelExportOptions &options)
ClosedInterval::Iterator begin(ClosedInterval interval)
absl::StatusOr< MPModelProto > ModelProtoFromLpFormat(absl::string_view model)
Definition lp_parser.cc:472
STL namespace.
if(!yyg->yy_init)
Definition parser.yy.cc:966
bool operator()(std::shared_ptr< Variable > lhs, std::shared_ptr< Variable > rhs) const