Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
math_opt_proto_utils.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 <algorithm>
17#include <cmath>
18#include <cstdint>
19#include <functional>
20#include <limits>
21#include <optional>
22#include <string>
23
24#include "absl/base/optimization.h"
25#include "absl/container/flat_hash_set.h"
26#include "absl/log/check.h"
27#include "absl/log/log.h"
28#include "absl/status/status.h"
29#include "absl/strings/string_view.h"
41
42namespace operations_research {
43namespace math_opt {
44namespace {
45constexpr double kInf = std::numeric_limits<double>::infinity();
46} // namespace
47
49 if (solve_result.termination().has_objective_bounds()) {
50 return solve_result.termination().objective_bounds();
51 }
52 ObjectiveBoundsProto objective_bounds;
53 objective_bounds.set_primal_bound(
54 solve_result.solve_stats().best_primal_bound());
55 objective_bounds.set_dual_bound(solve_result.solve_stats().best_dual_bound());
56 return objective_bounds;
57}
58
60 if (solve_result.termination().has_problem_status()) {
61 return solve_result.termination().problem_status();
62 }
63 ProblemStatusProto problem_status;
64 problem_status.set_primal_status(
65 solve_result.solve_stats().problem_status().primal_status());
66 problem_status.set_dual_status(
67 solve_result.solve_stats().problem_status().dual_status());
68 problem_status.set_primal_or_dual_infeasible(
70 return problem_status;
71}
72
74 CHECK_EQ(sparse_vector.ids_size(), sparse_vector.values_size());
75 // Keep track of the next index that has not yet been used for a non zero
76 // value.
77 int next = 0;
78 for (const auto [id, value] : MakeView(sparse_vector)) {
79 // Se use `!(== 0.0)` here so that we keep NaN values for which both `v ==
80 // 0` and `v != 0` returns false.
81 if (!(value == 0.0)) {
82 sparse_vector.set_ids(next, id);
83 sparse_vector.set_values(next, value);
84 ++next;
85 }
86 }
87 // At the end of the iteration, `next` contains the index of the first unused
88 // index. This means it contains the number of used elements.
89 sparse_vector.mutable_ids()->Truncate(next);
90 sparse_vector.mutable_values()->Truncate(next);
91}
92
94 const SparseVectorFilterProto& filter)
95 : filter_(filter) {
96 // We only do this test in non-optimized builds.
97 if (DEBUG_MODE && filter_.filter_by_ids()) {
98 // Checks that input filtered_ids are strictly increasing.
99 // That is: for all i, ids(i) < ids(i+1).
100 // Hence here we fail if there exists i such that ids(i) >= ids(i+1).
101 const auto& ids = filter_.filtered_ids();
102 CHECK(std::adjacent_find(ids.begin(), ids.end(),
103 std::greater_equal<int64_t>()) == ids.end())
104 << "The input filter.filtered_ids must be strictly increasing.";
105 }
106}
107
110 const SparseVectorFilterProto& filter) {
112 SparseVectorFilterPredicate predicate(filter);
113 for (const auto [id, val] : MakeView(input)) {
114 if (predicate.AcceptsAndUpdate(id, val)) {
115 result.add_ids(id);
116 result.add_values(val);
117 }
118 }
119 return result;
120}
121
122void ApplyAllFilters(const ModelSolveParametersProto& model_solve_params,
124 if (model_solve_params.has_variable_values_filter() &&
125 solution.has_primal_solution()) {
126 *solution.mutable_primal_solution()->mutable_variable_values() =
127 FilterSparseVector(solution.primal_solution().variable_values(),
128 model_solve_params.variable_values_filter());
129 }
130 if (model_solve_params.has_dual_values_filter() &&
131 solution.has_dual_solution()) {
132 *solution.mutable_dual_solution()->mutable_dual_values() =
133 FilterSparseVector(solution.dual_solution().dual_values(),
134 model_solve_params.dual_values_filter());
135 }
136 if (model_solve_params.has_reduced_costs_filter() &&
137 solution.has_dual_solution()) {
138 *solution.mutable_dual_solution()->mutable_reduced_costs() =
139 FilterSparseVector(solution.dual_solution().reduced_costs(),
140 model_solve_params.reduced_costs_filter());
141 }
142}
143
144absl::flat_hash_set<CallbackEventProto> EventSet(
145 const CallbackRegistrationProto& callback_registration) {
146 // Here we don't use for-range loop since for repeated enum fields, the type
147 // used in C++ is RepeatedField<int>. Using the generated getter instead
148 // guarantees type safety.
149 absl::flat_hash_set<CallbackEventProto> events;
150 for (int i = 0; i < callback_registration.request_registration_size(); ++i) {
151 events.emplace(callback_registration.request_registration(i));
152 }
153 return events;
154}
155
156TerminationProto TerminateForLimit(const LimitProto limit, const bool feasible,
157 const absl::string_view detail) {
158 TerminationProto result;
159 if (feasible) {
161 } else {
163 }
164 result.set_limit(limit);
165 if (!detail.empty()) {
166 result.set_detail(detail);
167 }
168 return result;
169}
170
172 const absl::string_view detail) {
173 return TerminateForLimit(limit, /*feasible=*/true, detail);
174}
175
177 const absl::string_view detail) {
178 return TerminateForLimit(limit, /*feasible=*/false, detail);
179}
180
182 const absl::string_view detail) {
183 TerminationProto result;
184 result.set_reason(reason);
185 if (!detail.empty()) {
186 result.set_detail(detail);
187 }
188 return result;
189}
190
193 bounds.set_primal_bound(is_maximize ? -kInf : +kInf);
194 bounds.set_dual_bound(is_maximize ? +kInf : -kInf);
195 return bounds;
196}
197
198namespace {
199ObjectiveBoundsProto MakeUnboundedBounds(const bool is_maximize) {
200 ObjectiveBoundsProto bounds;
201 bounds.set_primal_bound(is_maximize ? +kInf : -kInf);
202 bounds.set_dual_bound(bounds.primal_bound());
203 return bounds;
204}
205} // namespace
206
208 const TerminationReasonProto reason,
209 const absl::string_view detail) {
210 TerminationProto result;
211 result.set_reason(reason);
216 *result.mutable_objective_bounds() = MakeTrivialBounds(is_maximize);
217 if (!detail.empty()) {
218 result.set_detail(detail);
219 }
220 return result;
221}
222
223TerminationProto OptimalTerminationProto(const double finite_primal_objective,
224 const double dual_objective,
225 const absl::string_view detail) {
226 TerminationProto result;
228 result.mutable_objective_bounds()->set_primal_bound(finite_primal_objective);
229 result.mutable_objective_bounds()->set_dual_bound(dual_objective);
233 if (!detail.empty()) {
234 result.set_detail(detail);
235 }
236 return result;
237}
238
240 const absl::string_view detail) {
241 TerminationProto result;
247 *result.mutable_objective_bounds() = MakeUnboundedBounds(is_maximize);
248 if (!detail.empty()) {
249 result.set_detail(detail);
250 }
251 return result;
252}
253
255 bool is_maximize, const FeasibilityStatusProto dual_feasibility_status,
256 const absl::string_view detail) {
257 TerminationProto result;
261 result.mutable_problem_status()->set_dual_status(dual_feasibility_status);
262 *result.mutable_objective_bounds() = MakeTrivialBounds(is_maximize);
263 if (dual_feasibility_status == FEASIBILITY_STATUS_FEASIBLE) {
265 result.objective_bounds().primal_bound());
266 }
267 if (!detail.empty()) {
268 result.set_detail(detail);
269 }
270 return result;
271}
272
274 const bool is_maximize, const LimitProto limit,
275 const std::optional<double> optional_finite_primal_objective,
276 const std::optional<double> optional_dual_objective,
277 const absl::string_view detail) {
278 if (optional_finite_primal_objective.has_value()) {
279 return FeasibleTerminationProto(is_maximize, limit,
280 *optional_finite_primal_objective,
281 optional_dual_objective, detail);
282 }
283 return NoSolutionFoundTerminationProto(is_maximize, limit,
284 optional_dual_objective, detail);
285}
286
288 LimitProto limit, const double primal_objective,
289 const double dual_objective, const bool claim_dual_feasible_solution_exists,
290 const absl::string_view detail) {
291 TerminationProto result;
292 if (std::isfinite(primal_objective)) {
296 } else {
300 }
301 if (claim_dual_feasible_solution_exists) {
304 } else {
307 }
308 result.mutable_objective_bounds()->set_primal_bound(primal_objective);
309 result.mutable_objective_bounds()->set_dual_bound(dual_objective);
310 result.set_limit(limit);
311 if (!detail.empty()) {
312 result.set_detail(detail);
313 }
314 return result;
315}
316
318 const absl::string_view detail) {
320 is_maximize, LIMIT_CUTOFF, /*optional_dual_objective=*/std::nullopt,
321 detail);
322}
323
325 const bool is_maximize, const LimitProto limit,
326 const std::optional<double> optional_dual_objective,
327 const absl::string_view detail) {
328 TerminationProto result;
334 *result.mutable_objective_bounds() = MakeTrivialBounds(is_maximize);
335 if (optional_dual_objective.has_value()) {
336 result.mutable_objective_bounds()->set_dual_bound(*optional_dual_objective);
339 }
340 result.set_limit(limit);
341 if (!detail.empty()) {
342 result.set_detail(detail);
343 }
344 return result;
345}
346
348 const bool is_maximize, const LimitProto limit,
349 const double primal_objective,
350 const std::optional<double> optional_dual_objective,
351 const absl::string_view detail) {
352 TerminationProto result;
358 *result.mutable_objective_bounds() = MakeTrivialBounds(is_maximize);
359 result.mutable_objective_bounds()->set_primal_bound(primal_objective);
360 if (optional_dual_objective.has_value()) {
361 result.mutable_objective_bounds()->set_dual_bound(*optional_dual_objective);
364 }
365 result.set_limit(limit);
366 if (!detail.empty()) {
367 result.set_detail(detail);
368 }
369 return result;
370}
371
373 bool is_maximize, const FeasibilityStatusProto dual_feasibility_status,
374 const absl::string_view detail) {
375 TerminationProto result;
379 result.mutable_problem_status()->set_dual_status(dual_feasibility_status);
380 if (dual_feasibility_status == FEASIBILITY_STATUS_UNDETERMINED) {
382 }
383 *result.mutable_objective_bounds() = MakeTrivialBounds(is_maximize);
384 if (!detail.empty()) {
385 result.set_detail(detail);
386 }
387 return result;
388}
389
390absl::Status ModelIsSupported(const ModelProto& model,
391 const SupportedProblemStructures& support_menu,
392 const absl::string_view solver_name) {
393 const auto error_status = [solver_name](
394 const absl::string_view structure,
395 const SupportType support) -> absl::Status {
396 switch (support) {
399 << solver_name << " does not support " << structure;
402 << "MathOpt does not currently support " << solver_name
403 << " models with " << structure;
405 LOG(FATAL) << "Unexpected call with `kSupported`";
406 }
407 ABSL_UNREACHABLE();
408 };
409 if (const SupportType support = support_menu.integer_variables;
410 support != SupportType::kSupported) {
411 for (const bool is_integer : model.variables().integers()) {
412 if (is_integer) {
413 return error_status("integer variables", support);
414 }
415 }
416 }
417 if (const SupportType support = support_menu.multi_objectives;
418 support != SupportType::kSupported) {
419 if (!model.auxiliary_objectives().empty()) {
420 return error_status("multiple objectives", support);
421 }
422 }
423 if (const SupportType support = support_menu.quadratic_objectives;
424 support != SupportType::kSupported) {
425 if (!model.objective().quadratic_coefficients().row_ids().empty()) {
426 return error_status("quadratic objectives", support);
427 }
428 for (const auto& [_, objective] : model.auxiliary_objectives()) {
429 if (!objective.quadratic_coefficients().row_ids().empty()) {
430 return error_status("quadratic objectives", support);
431 }
432 }
433 }
434 if (const SupportType support = support_menu.quadratic_constraints;
435 support != SupportType::kSupported) {
436 if (!model.quadratic_constraints().empty()) {
437 return error_status("quadratic constraints", support);
438 }
439 }
440 if (const SupportType support = support_menu.second_order_cone_constraints;
441 support != SupportType::kSupported) {
442 if (!model.second_order_cone_constraints().empty()) {
443 return error_status("second-order cone constraints", support);
444 }
445 }
446 if (const SupportType support = support_menu.sos1_constraints;
447 support != SupportType::kSupported) {
448 if (!model.sos1_constraints().empty()) {
449 return error_status("sos1 constraints", support);
450 }
451 }
452 if (const SupportType support = support_menu.sos2_constraints;
453 support != SupportType::kSupported) {
454 if (!model.sos2_constraints().empty()) {
455 return error_status("sos2 constraints", support);
456 }
457 }
458 if (const SupportType support = support_menu.indicator_constraints;
459 support != SupportType::kSupported) {
460 if (!model.indicator_constraints().empty()) {
461 return error_status("indicator constraints", support);
462 }
463 }
464 return absl::OkStatus();
465}
466
468 const SupportedProblemStructures& support_menu) {
469 if (support_menu.integer_variables != SupportType::kSupported) {
470 for (const bool is_integer :
471 update.variable_updates().integers().values()) {
472 if (is_integer) {
473 return false;
474 }
475 }
476 for (const bool is_integer : update.new_variables().integers()) {
477 if (is_integer) {
478 return false;
479 }
480 }
481 }
482 if (support_menu.multi_objectives != SupportType::kSupported) {
483 if (!update.auxiliary_objectives_updates()
485 .empty() ||
486 !update.auxiliary_objectives_updates().new_objectives().empty() ||
488 return false;
489 }
490 }
491 if (support_menu.quadratic_objectives != SupportType::kSupported) {
492 if (!update.objective_updates()
494 .row_ids()
495 .empty()) {
496 return false;
497 }
498 for (const auto& [_, new_objective] :
500 if (!new_objective.quadratic_coefficients().row_ids().empty()) {
501 return false;
502 }
503 }
504 for (const auto& [_, objective_update] :
506 if (!objective_update.quadratic_coefficients().row_ids().empty()) {
507 return false;
508 }
509 }
510 }
511 // Duck-types that the proto parameter contains fields named `new_constraints`
512 // and `deleted_constraint_ids`. This is standard for "mapped" constraints.
513 const auto contains_new_or_deleted_constraints =
514 [](const auto& constraint_update) {
515 return !constraint_update.new_constraints().empty() ||
516 !constraint_update.deleted_constraint_ids().empty();
517 };
519 if (contains_new_or_deleted_constraints(
521 return false;
522 }
523 }
525 if (contains_new_or_deleted_constraints(
527 return false;
528 }
529 }
530 if (support_menu.sos1_constraints != SupportType::kSupported) {
531 if (contains_new_or_deleted_constraints(update.sos1_constraint_updates())) {
532 return false;
533 }
534 }
535 if (support_menu.sos2_constraints != SupportType::kSupported) {
536 if (contains_new_or_deleted_constraints(update.sos2_constraint_updates())) {
537 return false;
538 }
539 }
541 if (contains_new_or_deleted_constraints(
543 return false;
544 }
545 }
546 return true;
547}
548
550 const ModelSolveParametersProto& model_parameters,
551 const SupportedProblemStructures& support_menu,
552 const absl::string_view solver_name) {
553 const auto validate_support = [solver_name](
554 const absl::string_view structure,
555 const SupportType support) -> absl::Status {
556 switch (support) {
558 return absl::OkStatus();
561 << structure << " is not supported as " << solver_name
562 << " does not support multiple objectives";
565 << structure
566 << " is not supported as MathOpt does not currently support "
567 << solver_name << " models with multiple objectives";
568 }
569 return absl::OkStatus();
570 };
571 if (model_parameters.has_primary_objective_parameters()) {
572 RETURN_IF_ERROR(validate_support(
573 "ModelSolveParametersProto.primary_objective_parameters",
574 support_menu.multi_objectives));
575 }
576 if (!model_parameters.auxiliary_objective_parameters().empty()) {
577 RETURN_IF_ERROR(validate_support(
578 "ModelSolveParametersProto.auxiliary_objective_parameters",
579 support_menu.multi_objectives));
580 }
581 return absl::OkStatus();
582}
583
585 SolveResultProto& solve_result_proto) {
586 *solve_result_proto.mutable_termination()->mutable_problem_status() =
587 GetProblemStatus(solve_result_proto);
588 *solve_result_proto.mutable_solve_stats()->mutable_problem_status() =
589 GetProblemStatus(solve_result_proto);
590 *solve_result_proto.mutable_termination()->mutable_objective_bounds() =
591 GetObjectiveBounds(solve_result_proto);
592 solve_result_proto.mutable_solve_stats()->set_best_primal_bound(
593 solve_result_proto.termination().objective_bounds().primal_bound());
594 solve_result_proto.mutable_solve_stats()->set_best_dual_bound(
595 solve_result_proto.termination().objective_bounds().dual_bound());
596}
597
598} // namespace math_opt
599} // namespace operations_research
#define RETURN_IF_ERROR(expr)
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::ObjectiveProto > & new_objectives() const
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::ObjectiveUpdatesProto > & objective_updates() const
::operations_research::math_opt::CallbackEventProto request_registration(int index) const
const ::operations_research::math_opt::VariablesProto & variables() const
Definition model.pb.h:4464
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::QuadraticConstraintProto > & quadratic_constraints() const
Definition model.pb.h:4886
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::SosConstraintProto > & sos1_constraints() const
Definition model.pb.h:4950
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::SosConstraintProto > & sos2_constraints() const
Definition model.pb.h:4982
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::SecondOrderConeConstraintProto > & second_order_cone_constraints() const
Definition model.pb.h:4918
const ::operations_research::math_opt::ObjectiveProto & objective() const
Definition model.pb.h:4563
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::ObjectiveProto > & auxiliary_objectives() const
Definition model.pb.h:4662
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::IndicatorConstraintProto > & indicator_constraints() const
Definition model.pb.h:5014
const ::operations_research::math_opt::SparseVectorFilterProto & variable_values_filter() const
const ::operations_research::math_opt::SparseVectorFilterProto & reduced_costs_filter() const
const ::operations_research::math_opt::SparseVectorFilterProto & dual_values_filter() const
const ::google::protobuf::Map<::int64_t, ::operations_research::math_opt::ObjectiveParametersProto > & auxiliary_objective_parameters() const
const ::operations_research::math_opt::SosConstraintUpdatesProto & sos1_constraint_updates() const
const ::operations_research::math_opt::AuxiliaryObjectivesUpdatesProto & auxiliary_objectives_updates() const
const ::operations_research::math_opt::VariableUpdatesProto & variable_updates() const
const ::operations_research::math_opt::QuadraticConstraintUpdatesProto & quadratic_constraint_updates() const
const ::operations_research::math_opt::SosConstraintUpdatesProto & sos2_constraint_updates() const
const ::operations_research::math_opt::IndicatorConstraintUpdatesProto & indicator_constraint_updates() const
const ::operations_research::math_opt::ObjectiveUpdatesProto & objective_updates() const
const ::operations_research::math_opt::SecondOrderConeConstraintUpdatesProto & second_order_cone_constraint_updates() const
const ::operations_research::math_opt::VariablesProto & new_variables() const
const ::operations_research::math_opt::SparseDoubleMatrixProto & quadratic_coefficients() const
Definition model.pb.h:3004
const ::operations_research::math_opt::SparseDoubleMatrixProto & quadratic_coefficients() const
void set_primal_status(::operations_research::math_opt::FeasibilityStatusProto value)
Definition result.pb.h:1781
::operations_research::math_opt::FeasibilityStatusProto dual_status() const
Definition result.pb.h:1802
void set_dual_status(::operations_research::math_opt::FeasibilityStatusProto value)
Definition result.pb.h:1806
::operations_research::math_opt::FeasibilityStatusProto primal_status() const
Definition result.pb.h:1777
::operations_research::math_opt::TerminationProto *PROTOBUF_NONNULL mutable_termination()
Definition result.pb.h:2739
const ::operations_research::math_opt::SolveStatsProto & solve_stats() const
Definition result.pb.h:2934
::operations_research::math_opt::SolveStatsProto *PROTOBUF_NONNULL mutable_solve_stats()
Definition result.pb.h:2988
const ::operations_research::math_opt::TerminationProto & termination() const
Definition result.pb.h:2685
const ::operations_research::math_opt::ProblemStatusProto & problem_status() const
Definition result.pb.h:2010
::operations_research::math_opt::ProblemStatusProto *PROTOBUF_NONNULL mutable_problem_status()
Definition result.pb.h:2064
::google::protobuf::RepeatedField<::int64_t > *PROTOBUF_NONNULL mutable_ids()
::google::protobuf::RepeatedField< double > *PROTOBUF_NONNULL mutable_values()
SparseVectorFilterPredicate(const SparseVectorFilterProto &filter)
const ::operations_research::math_opt::ObjectiveBoundsProto & objective_bounds() const
Definition result.pb.h:2483
void set_limit(::operations_research::math_opt::LimitProto value)
Definition result.pb.h:2288
void set_detail(Arg_ &&arg, Args_... args)
::operations_research::math_opt::ObjectiveBoundsProto *PROTOBUF_NONNULL mutable_objective_bounds()
Definition result.pb.h:2537
::operations_research::math_opt::ProblemStatusProto *PROTOBUF_NONNULL mutable_problem_status()
Definition result.pb.h:2438
const ::operations_research::math_opt::ProblemStatusProto & problem_status() const
Definition result.pb.h:2384
void set_reason(::operations_research::math_opt::TerminationReasonProto value)
Definition result.pb.h:2263
const ::operations_research::math_opt::SparseBoolVectorProto & integers() const
TerminationProto TerminateForReason(const TerminationReasonProto reason, const absl::string_view detail)
absl::Status ModelIsSupported(const ModelProto &model, const SupportedProblemStructures &support_menu, const absl::string_view solver_name)
TerminationProto FeasibleTermination(const LimitProto limit, const absl::string_view detail)
void UpgradeSolveResultProtoForStatsMigration(SolveResultProto &solve_result_proto)
TerminationProto TerminateForLimit(const LimitProto limit, const bool feasible, const absl::string_view detail)
absl::Status ModelSolveParametersAreSupported(const ModelSolveParametersProto &model_parameters, const SupportedProblemStructures &support_menu, const absl::string_view solver_name)
absl::flat_hash_set< CallbackEventProto > EventSet(const CallbackRegistrationProto &callback_registration)
TerminationProto OptimalTerminationProto(const double finite_primal_objective, const double dual_objective, const absl::string_view detail)
TerminationProto LimitTerminationProto(const bool is_maximize, const LimitProto limit, const std::optional< double > optional_finite_primal_objective, const std::optional< double > optional_dual_objective, const absl::string_view detail)
TerminationProto InfeasibleOrUnboundedTerminationProto(bool is_maximize, const FeasibilityStatusProto dual_feasibility_status, const absl::string_view detail)
bool UpdateIsSupported(const ModelUpdateProto &update, const SupportedProblemStructures &support_menu)
ProblemStatusProto GetProblemStatus(const SolveResultProto &solve_result)
TerminationProto FeasibleTerminationProto(const bool is_maximize, const LimitProto limit, const double primal_objective, const std::optional< double > optional_dual_objective, const absl::string_view detail)
ObjectiveBoundsProto GetObjectiveBounds(const SolveResultProto &solve_result)
TerminationProto NoSolutionFoundTerminationProto(const bool is_maximize, const LimitProto limit, const std::optional< double > optional_dual_objective, const absl::string_view detail)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
TerminationProto NoSolutionFoundTermination(const LimitProto limit, const absl::string_view detail)
TerminationProto InfeasibleTerminationProto(bool is_maximize, const FeasibilityStatusProto dual_feasibility_status, const absl::string_view detail)
SparseDoubleVectorProto FilterSparseVector(const SparseDoubleVectorProto &input, const SparseVectorFilterProto &filter)
TerminationProto CutoffTerminationProto(bool is_maximize, const absl::string_view detail)
TerminationProto UnboundedTerminationProto(const bool is_maximize, const absl::string_view detail)
void RemoveSparseDoubleVectorZeros(SparseDoubleVectorProto &sparse_vector)
void ApplyAllFilters(const ModelSolveParametersProto &model_solve_params, SolutionProto &solution)
ObjectiveBoundsProto MakeTrivialBounds(const bool is_maximize)
OR-Tools root namespace.
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
const bool DEBUG_MODE
Definition radix_sort.h:266
StatusBuilder UnimplementedErrorBuilder()
StatusBuilder InvalidArgumentErrorBuilder()
static int input(yyscan_t yyscanner)