Google OR-Tools v9.12
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/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"
42#if defined(USE_SCIP)
44#endif // defined(USE_SCIP)
45#if defined(USE_HIGHS)
47#endif // defined(USE_HIGHS)
48#if defined(USE_PDLP)
50#endif // defined(USE_PDLP)
51#if defined(USE_LP_PARSER)
53#endif // defined(USE_LP_PARSER)
56
57namespace operations_research {
58namespace mb {
59
60// ModelBuilderHelper.
61
63 const ModelBuilderHelper& other_helper) {
64 model_ = other_helper.model();
65}
66
68 const MPModelExportOptions& options) {
70 .value_or("");
71}
72
74 const MPModelExportOptions& options) {
75 return operations_research::ExportModelAsLpFormat(model_, options)
76 .value_or("");
77}
78
79bool ModelBuilderHelper::WriteToMpsFile(const std::string& filename,
80 const MPModelExportOptions& options) {
81 return WriteModelToMpsFile(filename, model_, options).ok();
82}
83
84bool ModelBuilderHelper::ReadModelFromProtoFile(const std::string& filename) {
85 if (file::GetTextProto(filename, &model_, file::Defaults()).ok() ||
86 file::GetBinaryProto(filename, &model_, file::Defaults()).ok()) {
87 return true;
88 }
89 MPModelRequest request;
90 if (file::GetTextProto(filename, &request, file::Defaults()).ok() ||
91 file::GetBinaryProto(filename, &request, file::Defaults()).ok()) {
92 model_ = request.model();
93 return true;
94 }
95 return false;
96}
97
98bool ModelBuilderHelper::WriteModelToProtoFile(const std::string& filename) {
99 if (absl::EndsWith(filename, "txt")) {
100 return file::SetTextProto(filename, model_, file::Defaults()).ok();
101 } else {
102 return file::SetBinaryProto(filename, model_, file::Defaults()).ok();
103 }
104}
105
106// See comment in the header file why we need to wrap absl::Status code with
107// code having simpler APIs.
108bool ModelBuilderHelper::ImportFromMpsString(const std::string& mps_string) {
109 absl::StatusOr<MPModelProto> model_or =
111 if (!model_or.ok()) return false;
112 model_ = model_or.value();
113 return true;
114}
115
116bool ModelBuilderHelper::ImportFromMpsFile(const std::string& mps_file) {
117 absl::StatusOr<MPModelProto> model_or =
119 if (!model_or.ok()) return false;
120 model_ = model_or.value();
121 return true;
122}
123
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();
129 return true;
130}
131
132bool ModelBuilderHelper::ImportFromLpFile(const std::string& lp_file) {
133 std::string lp_data;
134 if (!file::GetContents(lp_file, &lp_data, file::Defaults()).ok()) {
135 return false;
136 }
137 absl::StatusOr<MPModelProto> model_or = ModelProtoFromLpFormat(lp_data);
138 if (!model_or.ok()) return false;
139 model_ = model_or.value();
140 return true;
141}
142#endif // #if defined(USE_LP_PARSER)
143
144const MPModelProto& ModelBuilderHelper::model() const { return model_; }
145
146MPModelProto* ModelBuilderHelper::mutable_model() { return &model_; }
147
149 const int index = model_.variable_size();
150 model_.add_variable();
151 return index;
152}
153
154void ModelBuilderHelper::SetVarLowerBound(int var_index, double lb) {
155 model_.mutable_variable(var_index)->set_lower_bound(lb);
156}
157
158void ModelBuilderHelper::SetVarUpperBound(int var_index, double ub) {
159 model_.mutable_variable(var_index)->set_upper_bound(ub);
160}
161
162void ModelBuilderHelper::SetVarIntegrality(int var_index, bool is_integer) {
163 model_.mutable_variable(var_index)->set_is_integer(is_integer);
164}
165
167 double coeff) {
168 model_.mutable_variable(var_index)->set_objective_coefficient(coeff);
169}
170
171void ModelBuilderHelper::SetVarName(int var_index, const std::string& name) {
172 model_.mutable_variable(var_index)->set_name(name);
173}
174
175double ModelBuilderHelper::VarLowerBound(int var_index) const {
176 return model_.variable(var_index).lower_bound();
177}
178
179double ModelBuilderHelper::VarUpperBound(int var_index) const {
180 return model_.variable(var_index).upper_bound();
181}
182
183bool ModelBuilderHelper::VarIsIntegral(int var_index) const {
184 return model_.variable(var_index).is_integer();
185}
186
188 return model_.variable(var_index).objective_coefficient();
189}
190
191std::string ModelBuilderHelper::VarName(int var_index) const {
192 return model_.variable(var_index).name();
193}
194
196 const int index = model_.constraint_size();
197 model_.add_constraint();
198 return index;
199}
200
201void ModelBuilderHelper::SetConstraintLowerBound(int ct_index, double lb) {
202 model_.mutable_constraint(ct_index)->set_lower_bound(lb);
203}
204
205void ModelBuilderHelper::SetConstraintUpperBound(int ct_index, double ub) {
206 model_.mutable_constraint(ct_index)->set_upper_bound(ub);
207}
208
210 MPConstraintProto* ct_proto = model_.mutable_constraint(ct_index);
211 ct_proto->clear_var_index();
212 ct_proto->clear_coefficient();
213}
214
215void ModelBuilderHelper::AddConstraintTerm(int ct_index, int var_index,
216 double coeff) {
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);
221}
222
223void ModelBuilderHelper::SafeAddConstraintTerm(int ct_index, int var_index,
224 double 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));
230 return;
231 }
232 }
233 // If we reach this point, the variable does not exist in the constraint yet,
234 // so we add it to the constraint as a new term.
235 ct_proto->add_var_index(var_index);
236 ct_proto->add_coefficient(coeff);
237}
238
240 const std::string& name) {
241 model_.mutable_constraint(ct_index)->set_name(name);
242}
243
244void ModelBuilderHelper::SetConstraintCoefficient(int ct_index, int var_index,
245 double coeff) {
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);
250 return;
251 }
252 }
253 // If we reach this point, the variable does not exist in the constraint yet,
254 // so we add it to the constraint as a newterm.
255 ct_proto->add_var_index(var_index);
256 ct_proto->add_coefficient(coeff);
257}
258
260 return model_.constraint(ct_index).lower_bound();
261}
262
264 return model_.constraint(ct_index).upper_bound();
265}
266
267std::string ModelBuilderHelper::ConstraintName(int ct_index) const {
268 return model_.constraint(ct_index).name();
269}
270
271std::vector<int> ModelBuilderHelper::ConstraintVarIndices(int ct_index) const {
272 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
273 return {ct_proto.var_index().begin(), ct_proto.var_index().end()};
274}
275
277 int ct_index) const {
278 const MPConstraintProto& ct_proto = model_.constraint(ct_index);
279 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
280}
281
283 const int index = model_.general_constraint_size();
284 // Create the mew constraint, and force the type to indicator ct.
285 model_.add_general_constraint()->mutable_indicator_constraint();
286 return index;
287}
288
290 const MPGeneralConstraintProto& gen = model_.general_constraint(ct_index);
291 return gen.general_constraint_case() ==
292 MPGeneralConstraintProto::kIndicatorConstraint;
293}
294
296 double lb) {
297 DCHECK(IsEnforcedConstraint(ct_index));
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);
302}
303
305 double ub) {
306 DCHECK(IsEnforcedConstraint(ct_index));
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);
311}
312
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();
319}
320
321void ModelBuilderHelper::AddEnforcedConstraintTerm(int ct_index, int var_index,
322 double coeff) {
323 DCHECK(IsEnforcedConstraint(ct_index));
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);
330}
331
333 int var_index,
334 double coeff) {
335 DCHECK(IsEnforcedConstraint(ct_index));
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));
343 return;
344 }
345 }
346 // If we reach this point, the variable does not exist in the constraint yet,
347 // so we add it to the constraint as a new term.
348 ct_proto->add_var_index(var_index);
349 ct_proto->add_coefficient(coeff);
350}
351
353 const std::string& name) {
354 model_.mutable_general_constraint(ct_index)->set_name(name);
355}
356
358 int var_index,
359 double coeff) {
360 DCHECK(IsEnforcedConstraint(ct_index));
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);
367 return;
368 }
369 }
370 // If we reach this point, the variable does not exist in the constraint yet,
371 // so we add it to the constraint as a new term.
372 ct_proto->add_var_index(var_index);
373 ct_proto->add_coefficient(coeff);
374}
375
377 int var_index) {
378 DCHECK(IsEnforcedConstraint(ct_index));
379 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
380 gen->mutable_indicator_constraint()->set_var_index(var_index);
381}
382
384 bool positive) {
385 DCHECK(IsEnforcedConstraint(ct_index));
386 MPGeneralConstraintProto* gen = model_.mutable_general_constraint(ct_index);
387 gen->mutable_indicator_constraint()->set_var_value(positive);
388}
389
391 DCHECK(IsEnforcedConstraint(ct_index));
392 return model_.general_constraint(ct_index)
393 .indicator_constraint()
394 .constraint()
395 .lower_bound();
396}
397
399 DCHECK(IsEnforcedConstraint(ct_index));
400 return model_.general_constraint(ct_index)
401 .indicator_constraint()
402 .constraint()
403 .upper_bound();
404}
405
406std::string ModelBuilderHelper::EnforcedConstraintName(int ct_index) const {
407 DCHECK(IsEnforcedConstraint(ct_index));
408 return model_.general_constraint(ct_index).name();
409}
410
412 int ct_index) const {
413 DCHECK(IsEnforcedConstraint(ct_index));
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()};
417}
418
420 int ct_index) const {
421 DCHECK(IsEnforcedConstraint(ct_index));
422 const MPConstraintProto& ct_proto =
423 model_.general_constraint(ct_index).indicator_constraint().constraint();
424 return {ct_proto.coefficient().begin(), ct_proto.coefficient().end()};
425}
426
428 DCHECK(IsEnforcedConstraint(ct_index));
429 return model_.general_constraint(ct_index).indicator_constraint().var_index();
430}
431
433 DCHECK(IsEnforcedConstraint(ct_index));
434 return model_.general_constraint(ct_index)
435 .indicator_constraint()
436 .var_value() != 0;
437}
438
439int ModelBuilderHelper::num_variables() const { return model_.variable_size(); }
440
442 return model_.constraint_size() + model_.general_constraint_size();
443}
444
445std::string ModelBuilderHelper::name() const { return model_.name(); }
446
447void ModelBuilderHelper::SetName(const std::string& name) {
448 model_.set_name(name);
449}
451 for (MPVariableProto& var : *model_.mutable_variable()) {
452 var.clear_objective_coefficient();
453 }
454}
455
456bool ModelBuilderHelper::maximize() const { return model_.maximize(); }
457
459 model_.set_maximize(maximize);
460}
461
463 return model_.objective_offset();
464}
465
467 model_.set_objective_offset(offset);
468}
469
470void ModelBuilderHelper::ClearHints() { model_.clear_solution_hint(); }
471
472void ModelBuilderHelper::AddHint(int var_index, double var_value) {
473 model_.mutable_solution_hint()->add_var_index(var_index);
474 model_.mutable_solution_hint()->add_var_value(var_value);
475}
476
477std::optional<MPSolutionResponse> ModelSolverHelper::SolveRequest(
478 const MPModelRequest& request) {
481 request.solver_type()))) {
482 return std::nullopt;
483 }
484 return SolveMPModel(request, &interrupter_);
485}
486
487namespace {
488SolveStatus MPSolverResponseStatusToSolveStatus(MPSolverResponseStatus s) {
489 switch (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:
518 default:
520 }
521}
522} // namespace
523
524ModelSolverHelper::ModelSolverHelper(const std::string& solver_name)
525 : evaluator_(this) {
526 if (solver_name.empty()) return;
528 if (!MPSolver::ParseSolverType(solver_name, &parsed_type)) {
529 VLOG(1) << "Unsupported type " << solver_name;
530 } else {
531 solver_type_ = static_cast<MPModelRequest::SolverType>(parsed_type);
532 }
533}
534
536 if (!solver_type_.has_value()) return false;
537 if (solver_type_.value() == MPModelRequest::GLOP_LINEAR_PROGRAMMING) {
538 return true;
539 }
540#ifdef USE_PDLP
541 if (solver_type_.value() == MPModelRequest::PDLP_LINEAR_PROGRAMMING) {
542 return true;
543 }
544#endif // USE_PDLP
545 if (solver_type_.value() == MPModelRequest::SAT_INTEGER_PROGRAMMING) {
546 return true;
547 }
548#ifdef USE_SCIP
549 if (solver_type_.value() == MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING) {
550 return true;
551 }
552#endif // USE_SCIP
553#ifdef USE_HIGHS
554 if (solver_type_.value() == MPModelRequest::HIGHS_LINEAR_PROGRAMMING ||
555 solver_type_.value() == MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING) {
556 return true;
557 }
558#endif // USE_HIGHS
559 if (solver_type_.value() ==
560 MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING ||
561 solver_type_.value() == MPModelRequest::GUROBI_LINEAR_PROGRAMMING) {
563 }
564 if (solver_type_.value() ==
565 MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING ||
566 solver_type_.value() == MPModelRequest::XPRESS_LINEAR_PROGRAMMING) {
568 }
569 return false;
570}
571
573 response_.reset();
574 if (!solver_type_.has_value()) {
575 response_->set_status(
576 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
577 return;
578 }
579
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());
586 }
587 if (!solver_specific_parameters_.empty()) {
588 request.set_solver_specific_parameters(solver_specific_parameters_);
589 }
590 switch (solver_type_.value()) {
591 case MPModelRequest::GLOP_LINEAR_PROGRAMMING: {
592 response_ =
593 GlopSolveProto(std::move(request), &interrupt_solve_, log_callback_);
594 break;
595 }
596 case MPModelRequest::SAT_INTEGER_PROGRAMMING: {
597 response_ = SatSolveProto(std::move(request), &interrupt_solve_,
598 log_callback_, nullptr);
599 break;
600 }
601#if defined(USE_SCIP)
602 case MPModelRequest::SCIP_MIXED_INTEGER_PROGRAMMING: {
603 // TODO(user): Enable log_callback support.
604 // TODO(user): Enable interrupt_solve.
605 const auto temp = ScipSolveProto(std::move(request));
606 if (temp.ok()) {
607 response_ = std::move(temp.value());
608 }
609 break;
610 }
611#endif // defined(USE_SCIP)
612#if defined(USE_PDLP)
613 case MPModelRequest::PDLP_LINEAR_PROGRAMMING: {
614 const auto temp = PdlpSolveProto(std::move(request));
615 if (temp.ok()) {
616 response_ = std::move(temp.value());
617 }
618 break;
619 }
620#endif // defined(USE_PDLP)
621 case MPModelRequest::
622 GUROBI_LINEAR_PROGRAMMING: // ABSL_FALLTHROUGH_INTENDED
623 case MPModelRequest::GUROBI_MIXED_INTEGER_PROGRAMMING: {
624 const auto temp = GurobiSolveProto(std::move(request));
625 if (temp.ok()) {
626 response_ = std::move(temp.value());
627 }
628 break;
629 }
630#if defined(USE_HIGHS)
631 case MPModelRequest::HIGHS_LINEAR_PROGRAMMING: // ABSL_FALLTHROUGH_INTENDED
632 case MPModelRequest::HIGHS_MIXED_INTEGER_PROGRAMMING: {
633 // TODO(user): Enable log_callback support.
634 // TODO(user): Enable interrupt_solve.
635 const auto temp = HighsSolveProto(std::move(request));
636 if (temp.ok()) {
637 response_ = std::move(temp.value());
638 }
639 break;
640 }
641#endif // defined(USE_HIGHS)
642 case MPModelRequest::
643 XPRESS_LINEAR_PROGRAMMING: // ABSL_FALLTHROUGH_INTENDED
644 case MPModelRequest::XPRESS_MIXED_INTEGER_PROGRAMMING: {
645 response_ = XPressSolveProto(request);
646 break;
647 }
648 default: {
649 response_->set_status(
650 MPSolverResponseStatus::MPSOLVER_SOLVER_TYPE_UNAVAILABLE);
651 }
652 }
653 if (response_->status() == MPSOLVER_OPTIMAL ||
654 response_->status() == MPSOLVER_FEASIBLE) {
655 model_of_last_solve_ = &model.model();
656 activities_.assign(model.num_constraints(),
657 std::numeric_limits<double>::quiet_NaN());
658 } else {
659 activities_.clear();
660 }
661}
662
664 std::function<void(const std::string&)> log_callback) {
665 log_callback_ = std::move(log_callback);
666}
667
669 MbLogCallback* log_callback) {
670 log_callback_ = [log_callback](const std::string& message) {
671 log_callback->NewMessage(message);
672 };
673}
674
675void ModelSolverHelper::ClearLogCallback() { log_callback_ = nullptr; }
676
678 interrupter_.Interrupt();
679 interrupt_solve_ = true;
680 return true;
681}
682
683bool ModelSolverHelper::has_response() const { return response_.has_value(); }
684
686 return response_.has_value() &&
687 (response_.value().status() ==
688 MPSolverResponseStatus::MPSOLVER_OPTIMAL ||
689 response_.value().status() ==
690 MPSolverResponseStatus::MPSOLVER_FEASIBLE);
691}
692
693const MPSolutionResponse& ModelSolverHelper::response() const {
694 return response_.value();
695}
696
698 if (!response_.has_value()) {
700 }
701 return MPSolverResponseStatusToSolveStatus(response_.value().status());
702}
703
705 if (!has_response()) return 0.0;
706 return response_.value().objective_value();
707}
708
710 if (!has_response()) return 0.0;
711 return response_.value().best_objective_bound();
712}
713
714double ModelSolverHelper::variable_value(int var_index) const {
715 if (!has_response()) return 0.0;
716 if (var_index >= response_.value().variable_value_size()) return 0.0;
717 return response_.value().variable_value(var_index);
718}
719
721 std::shared_ptr<LinearExpr> expr) const {
722 if (!has_response()) return 0.0;
723 evaluator_.Clear();
724 evaluator_.AddToProcess(expr, 1.0);
725 return evaluator_.Evaluate();
726}
727
728double ModelSolverHelper::reduced_cost(int var_index) const {
729 if (!has_response()) return 0.0;
730 if (var_index >= response_.value().reduced_cost_size()) return 0.0;
731 return response_.value().reduced_cost(var_index);
732}
733
734double ModelSolverHelper::dual_value(int ct_index) const {
735 if (!has_response()) return 0.0;
736 if (ct_index >= response_.value().dual_value_size()) return 0.0;
737 return response_.value().dual_value(ct_index);
738}
739
740double ModelSolverHelper::activity(int ct_index) {
741 if (!has_response() || ct_index >= activities_.size() ||
742 !model_of_last_solve_.has_value()) {
743 return 0.0;
744 }
745
746 if (std::isnan(activities_[ct_index])) {
747 const MPConstraintProto& ct_proto =
748 model_of_last_solve_.value()->constraint(ct_index);
749 double result = 0.0;
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);
753 }
754 activities_[ct_index] = result;
755 }
756 return activities_[ct_index];
757}
758
760 if (!has_response()) return "";
761 return response_.value().status_str();
762}
763
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();
768}
769
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();
774}
775
777 time_limit_in_second_ = limit;
778}
779
781 const std::string& solver_specific_parameters) {
782 solver_specific_parameters_ = solver_specific_parameters;
783}
784
785void ModelSolverHelper::EnableOutput(bool enabled) { solver_output_ = enabled; }
786
787// Expressions.
788std::shared_ptr<LinearExpr> LinearExpr::Term(std::shared_ptr<LinearExpr> expr,
789 double coeff) {
790 return std::make_shared<AffineExpr>(expr, coeff, 0.0);
791}
792
793std::shared_ptr<LinearExpr> LinearExpr::Affine(std::shared_ptr<LinearExpr> expr,
794 double coeff, double constant) {
795 if (coeff == 1.0 && constant == 0.0) return expr;
796 return std::make_shared<AffineExpr>(expr, coeff, constant);
797}
798
799std::shared_ptr<LinearExpr> LinearExpr::AffineCst(double value, double coeff,
800 double constant) {
801 return std::make_shared<FixedValue>(value * coeff + constant);
802}
803
804std::shared_ptr<LinearExpr> LinearExpr::Constant(double value) {
805 return std::make_shared<FixedValue>(value);
806}
807
808std::shared_ptr<LinearExpr> LinearExpr::Add(std::shared_ptr<LinearExpr> expr) {
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);
813}
814
815std::shared_ptr<LinearExpr> LinearExpr::AddFloat(double cst) {
816 if (cst == 0.0) return shared_from_this();
817 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, cst);
818}
819
820std::shared_ptr<LinearExpr> LinearExpr::Sub(std::shared_ptr<LinearExpr> expr) {
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);
826}
827
828std::shared_ptr<LinearExpr> LinearExpr::SubFloat(double cst) {
829 if (cst == 0.0) return shared_from_this();
830 return std::make_shared<AffineExpr>(shared_from_this(), 1.0, -cst);
831}
832
833std::shared_ptr<LinearExpr> LinearExpr::RSubFloat(double cst) {
834 return std::make_shared<AffineExpr>(shared_from_this(), -1.0, cst);
835}
836
837std::shared_ptr<LinearExpr> LinearExpr::MulFloat(double 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);
841}
842
843std::shared_ptr<LinearExpr> LinearExpr::Neg() {
844 return std::make_shared<AffineExpr>(shared_from_this(), -1, 0);
845}
846
847// Expression visitors.
848
849void ExprVisitor::AddToProcess(std::shared_ptr<LinearExpr> expr, double coeff) {
850 to_process_.push_back(std::make_pair(expr, coeff));
851}
852
853void ExprVisitor::AddConstant(double constant) { offset_ += constant; }
854
856 to_process_.clear();
857 offset_ = 0.0;
858}
859
860void ExprFlattener::AddVarCoeff(std::shared_ptr<Variable> var, double coeff) {
861 canonical_terms_[var] += coeff;
862}
863
864double ExprFlattener::Flatten(std::vector<std::shared_ptr<Variable>>* vars,
865 std::vector<double>* coeffs) {
866 while (!to_process_.empty()) {
867 const auto [expr, coeff] = to_process_.back();
868 to_process_.pop_back();
869 expr->Visit(*this, coeff);
870 }
871
872 vars->clear();
873 coeffs->clear();
874 for (const auto& [var, coeff] : canonical_terms_) {
875 if (coeff == 0.0) continue;
876 vars->push_back(var);
877 coeffs->push_back(coeff);
878 }
879
880 return offset_;
881}
882
883void ExprEvaluator::AddVarCoeff(std::shared_ptr<Variable> var, double coeff) {
884 offset_ += coeff * helper_->variable_value(var->index());
885}
886
888 offset_ = 0.0;
889 while (!to_process_.empty()) {
890 const auto [expr, coeff] = to_process_.back();
891 to_process_.pop_back();
892 expr->Visit(*this, coeff);
893 }
894 return offset_;
895}
896
897FlatExpr::FlatExpr(std::shared_ptr<LinearExpr> expr) {
898 ExprFlattener lin;
899 lin.AddToProcess(expr, 1.0);
900 offset_ = lin.Flatten(&vars_, &coeffs_);
901}
902
903FlatExpr::FlatExpr(std::shared_ptr<LinearExpr> pos,
904 std::shared_ptr<LinearExpr> neg) {
905 ExprFlattener lin;
906 lin.AddToProcess(pos, 1.0);
907 lin.AddToProcess(neg, -1.0);
908 offset_ = lin.Flatten(&vars_, &coeffs_);
909}
910
911FlatExpr::FlatExpr(const std::vector<std::shared_ptr<Variable>>& vars,
912 const std::vector<double>& coeffs, double offset)
913 : vars_(vars), coeffs_(coeffs), offset_(offset) {}
914
915FlatExpr::FlatExpr(double offset) : offset_(offset) {}
916
917std::vector<int> FlatExpr::VarIndices() const {
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());
922 }
923 return var_indices;
924}
925
926void FlatExpr::Visit(ExprVisitor& lin, double c) {
927 for (int i = 0; i < vars_.size(); ++i) {
928 lin.AddVarCoeff(vars_[i], coeffs_[i] * c);
929 }
930 lin.AddConstant(offset_ * c);
931}
932
933std::string FlatExpr::ToString() const {
934 if (vars_.empty()) {
935 return absl::StrCat(offset_);
936 }
937 std::string s;
938 int num_printed = 0;
939 for (int i = 0; i < vars_.size(); ++i) {
940 DCHECK_NE(coeffs_[i], 0.0);
941 ++num_printed;
942 if (num_printed > 5) {
943 absl::StrAppend(&s, " + ...");
944 break;
945 }
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());
951 } else {
952 absl::StrAppend(&s, coeffs_[i], " * ", vars_[i]->ToString());
953 }
954 } else {
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());
961 } else {
962 absl::StrAppend(&s, " - ", -coeffs_[i], " * ", vars_[i]->ToString());
963 }
964 }
965 }
966 // If there are no terms, just print the offset.
967 if (num_printed == 0) {
968 return absl::StrCat(offset_);
969 }
970
971 // If there is an offset, print it.
972 if (offset_ != 0.0) {
973 if (offset_ > 0.0) {
974 absl::StrAppend(&s, " + ", offset_);
975 } else {
976 absl::StrAppend(&s, " - ", -offset_);
977 }
978 }
979 return s;
980}
981
982std::string FlatExpr::DebugString() const {
983 std::string s = absl::StrCat(
984 "FlatExpr(",
985 absl::StrJoin(vars_, ", ",
986 [](std::string* out, std::shared_ptr<Variable> expr) {
987 absl::StrAppend(out, expr->DebugString());
988 }));
989 if (offset_ != 0.0) {
990 absl::StrAppend(&s, ", offset=", offset_);
991 }
992 absl::StrAppend(&s, ")");
993 return s;
994}
995
996void FixedValue::Visit(ExprVisitor& lin, double c) {
997 lin.AddConstant(value_ * c);
998}
999
1000std::string FixedValue::ToString() const { return absl::StrCat(value_); }
1001
1002std::string FixedValue::DebugString() const {
1003 return absl::StrCat("FixedValue(", value_, ")");
1004}
1005
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()),
1011 offset_(offset) {}
1012
1014 for (int i = 0; i < exprs_.size(); ++i) {
1015 lin.AddToProcess(exprs_[i], coeffs_[i] * c);
1016 }
1017 lin.AddConstant(offset_ * c);
1018}
1019
1020std::string WeightedSumArray::ToString() const {
1021 if (exprs_.empty()) {
1022 return absl::StrCat(offset_);
1023 }
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());
1034 } else {
1035 absl::StrAppend(&s, coeffs_[i], " * ", exprs_[i]->ToString());
1036 }
1037 } else {
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());
1044 } else {
1045 absl::StrAppend(&s, " - ", -coeffs_[i], " * ", exprs_[i]->ToString());
1046 }
1047 }
1048 }
1049 // If there are no terms, just print the offset.
1050 if (first_printed) {
1051 return absl::StrCat(offset_);
1052 }
1053
1054 // If there is an offset, print it.
1055 if (offset_ != 0.0) {
1056 if (offset_ > 0.0) {
1057 absl::StrAppend(&s, " + ", offset_);
1058 } else {
1059 absl::StrAppend(&s, " - ", -offset_);
1060 }
1061 }
1062 absl::StrAppend(&s, ")");
1063 return s;
1064}
1065
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());
1072 }),
1073 "], [", absl::StrJoin(coeffs_, "], "), offset_, ")");
1074}
1075
1076AffineExpr::AffineExpr(std::shared_ptr<LinearExpr> expr, double coeff,
1077 double offset)
1078 : expr_(expr), coeff_(coeff), offset_(offset) {}
1079
1080void AffineExpr::Visit(ExprVisitor& lin, double c) {
1081 lin.AddToProcess(expr_, c * coeff_);
1082 lin.AddConstant(offset_ * c);
1083}
1084
1085std::shared_ptr<LinearExpr> AffineExpr::AddFloat(double cst) {
1086 if (cst == 0.0) return shared_from_this();
1087 return LinearExpr::Affine(expr_, coeff_, offset_ + cst);
1088}
1089
1090std::shared_ptr<LinearExpr> AffineExpr::SubFloat(double cst) {
1091 if (cst == 0.0) return shared_from_this();
1092 return LinearExpr::Affine(expr_, coeff_, offset_ - cst);
1093}
1094
1095std::shared_ptr<LinearExpr> AffineExpr::RSubFloat(double cst) {
1096 return LinearExpr::Affine(expr_, -coeff_, cst - offset_);
1097}
1098
1099std::shared_ptr<LinearExpr> AffineExpr::MulFloat(double cst) {
1100 if (cst == 0.0) return std::make_shared<FixedValue>(0);
1101 if (cst == 1.0) return shared_from_this();
1102 return LinearExpr::Affine(expr_, coeff_ * cst, offset_ * cst);
1103}
1104
1105std::shared_ptr<LinearExpr> AffineExpr::Neg() {
1106 return LinearExpr::Affine(expr_, -coeff_, -offset_);
1107}
1108
1109std::string AffineExpr::ToString() const {
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());
1115 } else {
1116 absl::StrAppend(&s, coeff_, " * ", expr_->ToString());
1117 }
1118 if (offset_ > 0.0) {
1119 absl::StrAppend(&s, " + ", offset_);
1120 } else if (offset_ < 0.0) {
1121 absl::StrAppend(&s, " - ", -offset_);
1122 }
1123 absl::StrAppend(&s, ")");
1124 return s;
1125}
1126
1127std::string AffineExpr::DebugString() const {
1128 return absl::StrCat("AffineExpr(expr=", expr_->DebugString(),
1129 ", coeff=", coeff_, ", offset=", offset_, ")");
1130}
1131std::shared_ptr<BoundedLinearExpression> LinearExpr::Eq(
1132 std::shared_ptr<LinearExpr> rhs) {
1133 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs, 0.0,
1134 0.0);
1135}
1136
1137std::shared_ptr<BoundedLinearExpression> LinearExpr::EqCst(double rhs) {
1138 return std::make_shared<BoundedLinearExpression>(shared_from_this(), rhs,
1139 rhs);
1140}
1141
1142std::shared_ptr<BoundedLinearExpression> LinearExpr::Le(
1143 std::shared_ptr<LinearExpr> rhs) {
1144 return std::make_shared<BoundedLinearExpression>(
1145 shared_from_this(), rhs, -std::numeric_limits<double>::infinity(), 0.0);
1146}
1147
1148std::shared_ptr<BoundedLinearExpression> LinearExpr::LeCst(double rhs) {
1149 return std::make_shared<BoundedLinearExpression>(
1150 shared_from_this(), -std::numeric_limits<double>::infinity(), rhs);
1151}
1152
1153std::shared_ptr<BoundedLinearExpression> LinearExpr::Ge(
1154 std::shared_ptr<LinearExpr> rhs) {
1155 return std::make_shared<BoundedLinearExpression>(
1156 shared_from_this(), rhs, 0.0, std::numeric_limits<double>::infinity());
1157}
1158
1159std::shared_ptr<BoundedLinearExpression> LinearExpr::GeCst(double rhs) {
1160 return std::make_shared<BoundedLinearExpression>(
1161 shared_from_this(), rhs, std::numeric_limits<double>::infinity());
1162}
1163
1164bool VariableComparator::operator()(std::shared_ptr<Variable> lhs,
1165 std::shared_ptr<Variable> rhs) const {
1166 return lhs->index() < rhs->index();
1167}
1168
1171
1173 bool is_integral)
1174 : helper_(helper) {
1175 index_ = helper_->AddVar();
1176 helper_->SetVarLowerBound(index_, lb);
1177 helper_->SetVarUpperBound(index_, ub);
1178 helper_->SetVarIntegrality(index_, is_integral);
1179}
1180
1182 bool is_integral, const std::string& name)
1183 : helper_(helper) {
1184 index_ = helper_->AddVar();
1185 helper_->SetVarLowerBound(index_, lb);
1186 helper_->SetVarUpperBound(index_, ub);
1187 helper_->SetVarIntegrality(index_, is_integral);
1188 helper_->SetVarName(index_, name);
1189}
1190
1192 bool is_integral)
1193 : helper_(helper) {
1194 index_ = helper_->AddVar();
1195 helper_->SetVarLowerBound(index_, lb);
1196 helper_->SetVarUpperBound(index_, ub);
1197 helper_->SetVarIntegrality(index_, is_integral);
1198}
1199
1201 bool is_integral, const std::string& name)
1202 : helper_(helper) {
1203 index_ = helper_->AddVar();
1204 helper_->SetVarLowerBound(index_, lb);
1205 helper_->SetVarUpperBound(index_, ub);
1206 helper_->SetVarIntegrality(index_, is_integral);
1207 helper_->SetVarName(index_, name);
1208}
1209
1210std::string Variable::ToString() const {
1211 if (!helper_->VarName(index_).empty()) {
1212 return helper_->VarName(index_);
1213 } else {
1214 return absl::StrCat("Variable(", index_, ")");
1215 }
1216}
1217
1218std::string Variable::DebugString() const {
1219 return absl::StrCat("Variable(index=", index_,
1220 ", lb=", helper_->VarLowerBound(index_),
1221 ", ub=", helper_->VarUpperBound(index_),
1222 ", is_integral=", helper_->VarIsIntegral(index_),
1223 ", name=\'", helper_->VarName(index_), "')");
1224}
1225
1226std::string Variable::name() const {
1227 const std::string& var_name = helper_->VarName(index_);
1228 if (!var_name.empty()) return var_name;
1229 return absl::StrCat("variable#", index_);
1230}
1231
1232void Variable::SetName(const std::string& name) {
1233 helper_->SetVarName(index_, name);
1234}
1235
1236double Variable::lower_bounds() const { return helper_->VarLowerBound(index_); }
1237
1239 helper_->SetVarLowerBound(index_, lb);
1240}
1241
1242double Variable::upper_bound() const { return helper_->VarUpperBound(index_); }
1243
1245 helper_->SetVarUpperBound(index_, ub);
1246}
1247
1248bool Variable::is_integral() const { return helper_->VarIsIntegral(index_); }
1249
1251 helper_->SetVarIntegrality(index_, is_integral);
1252}
1253
1255 return helper_->VarObjectiveCoefficient(index_);
1256}
1257
1259 helper_->SetVarObjectiveCoefficient(index_, coeff);
1260}
1261
1263 std::shared_ptr<LinearExpr> expr, double lower_bound, double upper_bound) {
1264 FlatExpr flat_expr(expr);
1265 vars_ = flat_expr.vars();
1266 coeffs_ = flat_expr.coeffs();
1267 lower_bound_ = lower_bound - flat_expr.offset();
1268 upper_bound_ = upper_bound - flat_expr.offset();
1269}
1270
1272 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1273 double lower_bound, double upper_bound) {
1274 FlatExpr flat_expr(pos, neg);
1275 vars_ = flat_expr.vars();
1276 coeffs_ = flat_expr.coeffs();
1277 lower_bound_ = lower_bound - flat_expr.offset();
1278 upper_bound_ = upper_bound - flat_expr.offset();
1279}
1280
1282 std::shared_ptr<LinearExpr> expr, int64_t lower_bound,
1283 int64_t upper_bound) {
1284 FlatExpr flat_expr(expr);
1285 vars_ = flat_expr.vars();
1286 coeffs_ = flat_expr.coeffs();
1287 lower_bound_ = lower_bound - flat_expr.offset();
1288 upper_bound_ = upper_bound - flat_expr.offset();
1289}
1290
1292 std::shared_ptr<LinearExpr> pos, std::shared_ptr<LinearExpr> neg,
1293 int64_t lower_bound, int64_t upper_bound) {
1294 FlatExpr flat_expr(pos, neg);
1295 vars_ = flat_expr.vars();
1296 coeffs_ = flat_expr.coeffs();
1297 lower_bound_ = lower_bound - flat_expr.offset();
1298 upper_bound_ = upper_bound - flat_expr.offset();
1299}
1300
1301double BoundedLinearExpression::lower_bound() const { return lower_bound_; }
1302double BoundedLinearExpression::upper_bound() const { return upper_bound_; }
1303const std::vector<std::shared_ptr<Variable>>& BoundedLinearExpression::vars()
1304 const {
1305 return vars_;
1306}
1307const std::vector<double>& BoundedLinearExpression::coeffs() const {
1308 return coeffs_;
1309}
1311 std::string s;
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) {
1317 s = var_name;
1318 } else if (coeffs_[0] == -1) {
1319 s = absl::StrCat("-", var_name);
1320 } else {
1321 s = absl::StrCat(coeffs_[0], " * ", var_name);
1322 }
1323 } else {
1324 s = "(";
1325 for (int i = 0; i < vars_.size(); ++i) {
1326 const std::string var_name = vars_[i]->ToString();
1327 if (i == 0) {
1328 if (coeffs_[i] == 1) {
1329 absl::StrAppend(&s, var_name);
1330 } else if (coeffs_[i] == -1) {
1331 absl::StrAppend(&s, "-", var_name);
1332 } else {
1333 absl::StrAppend(&s, coeffs_[i], " * ", var_name);
1334 }
1335 } else {
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);
1342 } else {
1343 absl::StrAppend(&s, " - ", -coeffs_[i], " * ", var_name);
1344 }
1345 }
1346 }
1347 absl::StrAppend(&s, ")");
1348 }
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");
1354 } else {
1355 return absl::StrCat(s, " <= ", upper_bound_);
1356 }
1357 } else if (upper_bound_ == std::numeric_limits<double>::infinity()) {
1358 return absl::StrCat(s, " >= ", lower_bound_);
1359 } else {
1360 return absl::StrCat(lower_bound_, " <= ", s, " <= ", upper_bound_);
1361 }
1362}
1363
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());
1370 }),
1371 "], coeffs=[", absl::StrJoin(coeffs_, ", "),
1372 "], lower_bound=", lower_bound_, ", upper_bound=", upper_bound_, ")");
1373}
1374
1375bool BoundedLinearExpression::CastToBool(bool* result) const {
1376 const bool is_zero = lower_bound_ == 0.0 && upper_bound_ == 0.0;
1377 if (is_zero) {
1378 if (vars_.empty()) {
1379 *result = true;
1380 return true;
1381 } else if (vars_.size() == 2 && coeffs_[0] + coeffs_[1] == 0 &&
1382 std::abs(coeffs_[0]) == 1) {
1383 *result = false;
1384 return true;
1385 }
1386 }
1387 return false;
1388}
1389
1390} // namespace mb
1391} // namespace operations_research
static bool SupportsProblemType(OptimizationProblemType problem_type)
static
static bool ParseSolverType(absl::string_view solver_id, OptimizationProblemType *type)
static
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)
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
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 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)
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)
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)
void AddHint(int var_index, double var_value)
int AddVar()
Direct low level model building API.
void SetVarObjectiveCoefficient(int var_index, double coeff)
void SetConstraintName(int ct_index, const std::string &name)
bool ImportFromMpsString(const std::string &mps_string)
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)
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.
const MPSolutionResponse & response() const
void SetLogCallbackFromDirectorClass(MbLogCallback *log_callback)
double expression_value(std::shared_ptr< LinearExpr > expr) const
void SetTimeLimitInSeconds(double limit)
Solve parameters.
void SetLogCallback(std::function< void(const std::string &)> log_callback)
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::Status SetTextProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
Definition file.cc:337
absl::StatusOr< std::string > GetContents(absl::string_view path, Options options)
Definition file.cc:191
absl::Status SetBinaryProto(absl::string_view filename, const google::protobuf::Message &proto, Options options)
Definition file.cc:360
Options Defaults()
Definition file.h:107
absl::Status GetTextProto(absl::string_view filename, google::protobuf::Message *proto, Options options)
Definition file.cc:327
absl::Status GetBinaryProto(const absl::string_view filename, google::protobuf::Message *proto, Options options)
Definition file.cc:348
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.
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.
if(!yyg->yy_init)
Definition parser.yy.cc:965
bool operator()(std::shared_ptr< Variable > lhs, std::shared_ptr< Variable > rhs) const