24#include "absl/base/nullability.h"
25#include "absl/cleanup/cleanup.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/log/check.h"
28#include "absl/log/log.h"
29#include "absl/memory/memory.h"
30#include "absl/status/status.h"
31#include "absl/status/statusor.h"
32#include "absl/strings/str_cat.h"
33#include "absl/strings/str_join.h"
34#include "absl/strings/str_split.h"
35#include "absl/strings/string_view.h"
36#include "absl/time/clock.h"
37#include "absl/time/time.h"
38#include "absl/types/span.h"
75absl::string_view SafeName(
const VariablesProto& variables,
int index) {
76 if (variables.names().empty()) {
79 return variables.names(index);
84 if (linear_constraints.names().empty()) {
87 return linear_constraints.names(index);
90absl::StatusOr<TerminationProto> BuildTermination(
92 const SolveInterrupter* absl_nullable
const interrupter,
93 const bool is_maximize,
const double objective_value) {
122 is_maximize, interrupter !=
nullptr && interrupter->IsInterrupted()
133 interrupter !=
nullptr && interrupter->IsInterrupted()
145 interrupter !=
nullptr && interrupter->IsInterrupted()
153 return absl::InternalError(
154 absl::StrCat(
"Unexpected GLOP termination reason: ",
157 LOG(FATAL) <<
"Unimplemented GLOP termination reason: "
162absl::Status ValidateGlopParameters(
const glop::GlopParameters& parameters) {
164 if (!error.empty()) {
166 <<
"invalid GlopParameters: " << error;
168 return absl::OkStatus();
173GlopSolver::GlopSolver() : linear_program_(), lp_solver_() {}
175void GlopSolver::AddVariables(
const VariablesProto& variables) {
177 const glop::ColIndex col_index = linear_program_.CreateNewVariable();
178 linear_program_.SetVariableBounds(col_index, variables.lower_bounds(i),
179 variables.upper_bounds(i));
180 linear_program_.SetVariableName(col_index, SafeName(variables, i));
188template <
typename IndexType>
191 IndexType num_indices,
192 absl::flat_hash_map<int64_t, IndexType>& id_index_map) {
194 num_indices.value(), IndexType(0));
195 IndexType new_index(0);
196 for (IndexType index(0); index < num_indices; ++index) {
197 if (indices_to_delete[index]) {
199 new_indices[index] = IndexType(-1);
201 new_indices[index] = new_index;
205 for (
auto it = id_index_map.begin(); it != id_index_map.end();) {
206 IndexType index = it->second;
207 if (indices_to_delete[index]) {
209 id_index_map.erase(it++);
211 it->second = new_indices[index];
217void GlopSolver::DeleteVariables(absl::Span<const int64_t> ids_to_delete) {
218 const glop::ColIndex num_cols = linear_program_.num_variables();
221 for (
const int64_t deleted_variable_id : ids_to_delete) {
222 columns_to_delete[variables_.at(deleted_variable_id)] =
true;
224 linear_program_.DeleteColumns(columns_to_delete);
225 UpdateIdIndexMap<glop::ColIndex>(columns_to_delete, num_cols, variables_);
228void GlopSolver::DeleteLinearConstraints(
229 absl::Span<const int64_t> ids_to_delete) {
230 const glop::RowIndex num_rows = linear_program_.num_constraints();
231 glop::DenseBooleanColumn rows_to_delete(num_rows,
false);
232 for (
const int64_t deleted_constraint_id : ids_to_delete) {
233 rows_to_delete[linear_constraints_.at(deleted_constraint_id)] =
true;
235 linear_program_.DeleteRows(rows_to_delete);
236 UpdateIdIndexMap<glop::RowIndex>(rows_to_delete, num_rows,
237 linear_constraints_);
240void GlopSolver::AddLinearConstraints(
241 const LinearConstraintsProto& linear_constraints) {
243 const glop::RowIndex row_index = linear_program_.CreateNewConstraint();
244 linear_program_.SetConstraintBounds(row_index,
245 linear_constraints.lower_bounds(i),
246 linear_constraints.upper_bounds(i));
247 linear_program_.SetConstraintName(row_index,
248 SafeName(linear_constraints, i));
254void GlopSolver::SetOrUpdateObjectiveCoefficients(
255 const SparseDoubleVectorProto& linear_objective_coefficients) {
256 for (
int i = 0;
i < linear_objective_coefficients.ids_size(); ++
i) {
257 const glop::ColIndex col_index =
258 variables_.at(linear_objective_coefficients.ids(i));
259 linear_program_.SetObjectiveCoefficient(
260 col_index, linear_objective_coefficients.values(i));
264void GlopSolver::SetOrUpdateConstraintMatrix(
265 const SparseDoubleMatrixProto& linear_constraint_matrix) {
267 const glop::ColIndex col_index =
268 variables_.at(linear_constraint_matrix.column_ids(j));
269 const glop::RowIndex row_index =
270 linear_constraints_.at(linear_constraint_matrix.row_ids(j));
271 const double coefficient = linear_constraint_matrix.coefficients(j);
272 linear_program_.SetCoefficient(row_index, col_index, coefficient);
276void GlopSolver::UpdateVariableBounds(
277 const VariableUpdatesProto& variable_updates) {
278 for (
const auto [
id, lb] :
MakeView(variable_updates.lower_bounds())) {
279 const auto col_index = variables_.at(
id);
280 linear_program_.SetVariableBounds(
281 col_index, lb, linear_program_.variable_upper_bounds()[col_index]);
283 for (
const auto [
id, ub] :
MakeView(variable_updates.upper_bounds())) {
284 const auto col_index = variables_.at(
id);
285 linear_program_.SetVariableBounds(
286 col_index, linear_program_.variable_lower_bounds()[col_index], ub);
290void GlopSolver::UpdateLinearConstraintBounds(
291 const LinearConstraintUpdatesProto& linear_constraint_updates) {
292 for (
const auto [
id, lb] :
293 MakeView(linear_constraint_updates.lower_bounds())) {
294 const auto row_index = linear_constraints_.at(
id);
295 linear_program_.SetConstraintBounds(
296 row_index, lb, linear_program_.constraint_upper_bounds()[row_index]);
298 for (
const auto [
id, ub] :
299 MakeView(linear_constraint_updates.upper_bounds())) {
300 const auto row_index = linear_constraints_.at(
id);
301 linear_program_.SetConstraintBounds(
302 row_index, linear_program_.constraint_lower_bounds()[row_index], ub);
308 const bool setting_initial_basis,
const bool has_message_callback,
309 const bool is_maximization) {
312 <<
"invalid SolveParametersProto.glop value";
315 std::vector<std::string> warnings;
317 const absl::Duration time_limit =
321 if (has_message_callback) {
339 const int random_seed = std::max(0, solve_parameters.
random_seed());
347 warnings.emplace_back(
"GLOP does snot support 'node_limit' parameter");
359 warnings.emplace_back(absl::StrCat(
360 "GLOP does not support the 'lp_algorithm' parameter value: ",
366 switch (solve_parameters.
scaling()) {
378 LOG(FATAL) <<
"Scaling emphasis: "
380 <<
" unknown, error setting GLOP parameters";
383 if (setting_initial_basis) {
387 switch (solve_parameters.
presolve()) {
398 LOG(FATAL) <<
"Presolve emphasis: "
400 <<
" unknown, error setting GLOP parameters";
404 warnings.push_back(absl::StrCat(
405 "GLOP does not support 'cuts' parameters, but cuts was set to: ",
410 absl::StrCat(
"GLOP does not support 'heuristics' parameter, but "
411 "heuristics was set to: ",
415 warnings.push_back(
"GLOP does not support 'cutoff_limit' parameter");
419 const auto set_upper_limit_if_missing = [&result](
const double limit) {
425 const auto set_lower_limit_if_missing = [&result](
const double limit) {
431 if (is_maximization) {
438 if (is_maximization) {
445 warnings.push_back(
"GLOP does not support 'solution_limit' parameter");
447 if (!warnings.empty()) {
448 return absl::InvalidArgumentError(absl::StrJoin(warnings,
"; "));
457 <<
"invalid GlopParameters generated from SolveParametersProto";
462template <
typename IndexType>
464 absl::Span<const int64_t> ids_in_order,
465 const absl::flat_hash_map<int64_t, IndexType>& id_map,
470 for (
const int64_t variable_id : ids_in_order) {
471 const double value = values[id_map.at(variable_id)];
481template <
typename ValueType>
483 switch (glop_basis_status) {
484 case ValueType::BASIC:
486 case ValueType::FIXED_VALUE:
488 case ValueType::AT_LOWER_BOUND:
490 case ValueType::AT_UPPER_BOUND:
492 case ValueType::FREE:
498template <
typename IndexType,
typename ValueType>
500 absl::Span<const int64_t> ids_in_order,
501 const absl::flat_hash_map<int64_t, IndexType>& id_map,
504 for (
const int64_t variable_id : ids_in_order) {
505 const ValueType value = values[id_map.at(variable_id)];
513template <
typename ValueType>
515 switch (basis_status) {
517 return ValueType::BASIC;
519 return ValueType::FIXED_VALUE;
521 return ValueType::AT_LOWER_BOUND;
523 return ValueType::AT_UPPER_BOUND;
525 return ValueType::FREE;
527 LOG(FATAL) <<
"Unexpected invalid initial_basis.";
528 return ValueType::FREE;
534 const absl::flat_hash_map<int64_t, T>& id_map) {
535 std::vector<int64_t> sorted;
536 sorted.reserve(id_map.size());
537 for (
const auto& entry : id_map) {
538 sorted.emplace_back(entry.first);
540 std::sort(sorted.begin(), sorted.end());
549 const absl::flat_hash_map<int64_t, T>& id_map) {
551 constexpr int64_t kEmptyId = -1;
553 for (
const auto& [
id, index] : id_map) {
554 CHECK(index >= 0 && index < index_to_id.
size()) << index;
555 CHECK_EQ(index_to_id[index], kEmptyId);
556 index_to_id[index] = id;
566InvertedBounds GlopSolver::ListInvertedBounds()
const {
568 std::vector<glop::ColIndex> inverted_columns;
569 const glop::ColIndex num_cols = linear_program_.num_variables();
570 for (glop::ColIndex col(0); col < num_cols; ++col) {
571 if (linear_program_.variable_lower_bounds()[col] >
572 linear_program_.variable_upper_bounds()[col]) {
573 inverted_columns.push_back(col);
576 std::vector<glop::RowIndex> inverted_rows;
577 const glop::RowIndex num_rows = linear_program_.num_constraints();
578 for (glop::RowIndex row(0); row < num_rows; ++row) {
579 if (linear_program_.constraint_lower_bounds()[row] >
580 linear_program_.constraint_upper_bounds()[row]) {
581 inverted_rows.push_back(row);
587 InvertedBounds inverted_bounds;
588 if (!inverted_columns.empty()) {
589 const glop::StrictITIVector<glop::ColIndex, int64_t> ids =
591 CHECK_EQ(ids.size(), num_cols);
592 inverted_bounds.variables.reserve(inverted_columns.size());
593 for (
const glop::ColIndex col : inverted_columns) {
594 inverted_bounds.variables.push_back(ids[col]);
597 if (!inverted_rows.empty()) {
598 const glop::StrictITIVector<glop::RowIndex, int64_t> ids =
600 CHECK_EQ(ids.size(), num_rows);
601 inverted_bounds.linear_constraints.reserve(inverted_rows.size());
602 for (
const glop::RowIndex row : inverted_rows) {
603 inverted_bounds.linear_constraints.push_back(ids[row]);
607 return inverted_bounds;
610void GlopSolver::FillSolution(
const glop::ProblemStatus status,
611 const ModelSolveParametersProto& model_parameters,
612 SolveResultProto& solve_result) {
617 const bool phase_I_solution_available =
618 (status == glop::ProblemStatus::INIT) &&
619 (lp_solver_.GetNumberOfSimplexIterations() > 0);
620 if (status != glop::ProblemStatus::OPTIMAL &&
621 status != glop::ProblemStatus::PRIMAL_FEASIBLE &&
622 status != glop::ProblemStatus::DUAL_FEASIBLE &&
623 status != glop::ProblemStatus::PRIMAL_UNBOUNDED &&
624 status != glop::ProblemStatus::DUAL_UNBOUNDED &&
625 !phase_I_solution_available) {
629 auto sorted_constraints =
GetSortedIs(linear_constraints_);
630 SolutionProto*
const solution = solve_result.add_solutions();
631 BasisProto*
const basis =
solution->mutable_basis();
633 solution->mutable_primal_solution();
634 DualSolutionProto*
const dual_solution =
solution->mutable_dual_solution();
639 if (status == glop::ProblemStatus::OPTIMAL) {
641 basis->set_basic_dual_feasibility(SOLUTION_STATUS_FEASIBLE);
642 dual_solution->set_feasibility_status(SOLUTION_STATUS_FEASIBLE);
643 }
else if (status == glop::ProblemStatus::PRIMAL_FEASIBLE) {
648 dual_solution->set_feasibility_status(SOLUTION_STATUS_UNDETERMINED);
649 basis->set_basic_dual_feasibility(SOLUTION_STATUS_INFEASIBLE);
650 }
else if (status == glop::ProblemStatus::DUAL_FEASIBLE) {
657 dual_solution->set_feasibility_status(SOLUTION_STATUS_FEASIBLE);
658 basis->set_basic_dual_feasibility(SOLUTION_STATUS_FEASIBLE);
661 if (lp_solver_.GetParameters().use_dual_simplex()) {
666 dual_solution->set_feasibility_status(SOLUTION_STATUS_INFEASIBLE);
667 basis->set_basic_dual_feasibility(SOLUTION_STATUS_INFEASIBLE);
671 dual_solution->set_feasibility_status(SOLUTION_STATUS_UNDETERMINED);
672 basis->set_basic_dual_feasibility(SOLUTION_STATUS_UNDETERMINED);
678 if (basis->basic_dual_feasibility() == SOLUTION_STATUS_FEASIBLE) {
680 dual_solution->set_objective_value(
primal_solution->objective_value());
684 *basis->mutable_constraint_status() = *basis->mutable_variable_status() =
686 lp_solver_.variable_statuses());
687 *basis->mutable_constraint_status() =
689 lp_solver_.constraint_statuses());
692 sorted_variables, variables_, lp_solver_.variable_values(),
693 model_parameters.variable_values_filter());
696 sorted_constraints, linear_constraints_, lp_solver_.dual_values(),
697 model_parameters.dual_values_filter());
699 sorted_variables, variables_, lp_solver_.reduced_costs(),
700 model_parameters.reduced_costs_filter());
702 if (!lp_solver_.primal_ray().empty()) {
703 PrimalRayProto*
const primal_ray = solve_result.add_primal_rays();
706 sorted_variables, variables_, lp_solver_.primal_ray(),
707 model_parameters.variable_values_filter());
709 if (!lp_solver_.constraints_dual_ray().empty() &&
710 !lp_solver_.variable_bounds_dual_ray().empty()) {
711 DualRayProto*
const dual_ray = solve_result.add_dual_rays();
712 *dual_ray->mutable_dual_values() =
714 lp_solver_.constraints_dual_ray(),
715 model_parameters.dual_values_filter());
717 sorted_variables, variables_, lp_solver_.variable_bounds_dual_ray(),
718 model_parameters.reduced_costs_filter());
722absl::Status GlopSolver::FillSolveStats(
const absl::Duration solve_time,
723 SolveStatsProto& solve_stats) {
725 solve_stats.set_simplex_iterations(lp_solver_.GetNumberOfSimplexIterations());
727 solve_time, solve_stats.mutable_solve_time()));
729 return absl::OkStatus();
732absl::StatusOr<SolveResultProto> GlopSolver::MakeSolveResult(
733 const glop::ProblemStatus status,
734 const ModelSolveParametersProto& model_parameters,
735 const SolveInterrupter* absl_nullable
const interrupter,
736 const absl::Duration solve_time) {
737 SolveResultProto solve_result;
739 BuildTermination(status, interrupter,
740 linear_program_.IsMaximizationProblem(),
741 lp_solver_.GetObjectiveValue()));
742 FillSolution(status, model_parameters, solve_result);
744 FillSolveStats(solve_time, *solve_result.mutable_solve_stats()));
748void GlopSolver::SetGlopBasis(
const BasisProto& basis) {
749 glop::VariableStatusRow variable_statuses(linear_program_.num_variables());
750 for (
const auto [
id, value] :
MakeView(basis.variable_status())) {
751 variable_statuses[variables_.at(
id)] =
752 ToGlopBasisStatus<glop::VariableStatus>(
755 glop::ConstraintStatusColumn constraint_statuses(
756 linear_program_.num_constraints());
757 for (
const auto [
id, value] :
MakeView(basis.constraint_status())) {
758 constraint_statuses[linear_constraints_.at(
id)] =
759 ToGlopBasisStatus<glop::ConstraintStatus>(
762 lp_solver_.SetInitialBasis(variable_statuses, constraint_statuses);
772 model_parameters, kGlopSupportedStructures,
"Glop"));
776 const absl::Time start = absl::Now();
782 message_cb !=
nullptr,
783 linear_program_.IsMaximizationProblem()));
784 lp_solver_.SetParameters(glop_parameters);
790 std::atomic<bool> interrupt_solve =
false;
791 const std::unique_ptr<TimeLimit> time_limit =
793 time_limit->RegisterExternalBooleanAsLimit(&interrupt_solve);
796 CHECK_NE(interrupter,
nullptr);
797 interrupt_solve =
true;
800 if (message_cb !=
nullptr) {
808 CHECK_EQ(lp_solver_.GetSolverLogger().NumInfoLoggingCallbacks(), 0);
809 lp_solver_.GetSolverLogger().AddInfoLoggingCallback(
810 [&](absl::string_view message) {
811 message_cb(absl::StrSplit(message,
'\n'));
814 const auto message_cb_cleanup = absl::MakeCleanup([&]() {
815 if (message_cb !=
nullptr) {
817 CHECK_EQ(lp_solver_.GetSolverLogger().NumInfoLoggingCallbacks(), 1);
818 lp_solver_.GetSolverLogger().ClearInfoLoggingCallbacks();
828 lp_solver_.SolveWithTimeLimit(linear_program_, time_limit.get());
829 const absl::Duration solve_time = absl::Now() - start;
830 return MakeSolveResult(status, model_parameters, interrupter, solve_time);
836 auto solver = absl::WrapUnique(
new GlopSolver);
840 solver->linear_program_.SetDcheckBounds(
false);
842 solver->linear_program_.SetName(model.
name());
844 solver->linear_program_.SetObjectiveOffset(model.
objective().
offset());
847 solver->SetOrUpdateObjectiveCoefficients(
852 solver->linear_program_.CleanUp();
862 linear_program_.SetMaximizationProblem(
866 linear_program_.SetObjectiveOffset(
873 SetOrUpdateObjectiveCoefficients(
883 linear_program_.CleanUp();
888absl::StatusOr<ComputeInfeasibleSubsystemResultProto>
892 return absl::UnimplementedError(
893 "GLOP does not implement a method to compute an infeasible subsystem");
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
static std::unique_ptr< TimeLimit > FromParameters(const Parameters ¶meters)
bool has_random_seed() const
bool has_objective_lower_limit() const
bool has_log_search_progress() const
bool has_use_scaling() const
static constexpr ScalingAlgorithm EQUILIBRATION
void set_log_to_stdout(bool value)
bool has_scaling_method() const
void set_scaling_method(::operations_research::glop::GlopParameters_ScalingAlgorithm value)
void set_num_omp_threads(::int32_t value)
void set_objective_lower_limit(double value)
bool has_objective_upper_limit() const
bool has_num_omp_threads() const
void set_random_seed(::int32_t value)
void set_use_dual_simplex(bool value)
bool has_max_time_in_seconds() const
bool has_max_number_of_iterations() const
void set_max_time_in_seconds(double value)
bool has_use_dual_simplex() const
void set_max_number_of_iterations(::int64_t value)
bool has_use_preprocessing() const
void set_objective_upper_limit(double value)
void set_log_search_progress(bool value)
void set_use_scaling(bool value)
void set_use_preprocessing(bool value)
absl::StatusOr< ComputeInfeasibleSubsystemResultProto > ComputeInfeasibleSubsystem(const SolveParametersProto ¶meters, MessageCallback message_cb, const SolveInterrupter *absl_nullable interrupter) override
absl::StatusOr< bool > Update(const ModelUpdateProto &model_update) override
absl::StatusOr< SolveResultProto > Solve(const SolveParametersProto ¶meters, const ModelSolveParametersProto &model_parameters, MessageCallback message_cb, const CallbackRegistrationProto &callback_registration, Callback cb, const SolveInterrupter *absl_nullable interrupter) override
static absl::StatusOr< glop::GlopParameters > MergeSolveParameters(const SolveParametersProto &solve_parameters, bool setting_initial_basis, bool has_message_callback, bool is_maximization)
static absl::StatusOr< std::unique_ptr< SolverInterface > > New(const ModelProto &model, const InitArgs &init_args)
const ::operations_research::math_opt::VariablesProto & variables() const
const ::operations_research::math_opt::LinearConstraintsProto & linear_constraints() const
const ::std::string & name() const
const ::operations_research::math_opt::ObjectiveProto & objective() const
const ::operations_research::math_opt::SparseDoubleMatrixProto & linear_constraint_matrix() const
const ::operations_research::math_opt::BasisProto & initial_basis() const
bool has_initial_basis() const
::int64_t deleted_linear_constraint_ids(int index) const
const ::operations_research::math_opt::SparseDoubleMatrixProto & linear_constraint_matrix_updates() const
const ::operations_research::math_opt::LinearConstraintsProto & new_linear_constraints() const
const ::operations_research::math_opt::VariableUpdatesProto & variable_updates() const
const ::operations_research::math_opt::ObjectiveUpdatesProto & objective_updates() const
const ::operations_research::math_opt::LinearConstraintUpdatesProto & linear_constraint_updates() const
::int64_t deleted_variable_ids(int index) const
const ::operations_research::math_opt::VariablesProto & new_variables() const
const ::operations_research::math_opt::SparseDoubleVectorProto & linear_coefficients() const
double offset_update() const
const ::operations_research::math_opt::SparseDoubleVectorProto & linear_coefficients() const
bool direction_update() const
bool has_direction_update() const
bool has_offset_update() const
::operations_research::math_opt::EmphasisProto presolve() const
bool has_cutoff_limit() const
::int32_t threads() const
bool has_objective_limit() const
bool has_random_seed() const
bool has_solution_limit() const
const ::operations_research::glop::GlopParameters & glop() const
::operations_research::math_opt::EmphasisProto scaling() const
::int32_t random_seed() const
::operations_research::math_opt::EmphasisProto heuristics() const
bool has_node_limit() const
double objective_limit() const
bool enable_output() const
double best_bound_limit() const
::operations_research::math_opt::LPAlgorithmProto lp_algorithm() const
::int64_t iteration_limit() const
bool has_best_bound_limit() const
const ::google::protobuf::Duration & time_limit() const
bool has_time_limit() const
::operations_research::math_opt::EmphasisProto cuts() const
std::function< void(const std::vector< std::string > &)> MessageCallback
std::function< absl::StatusOr< CallbackResultProto >( const CallbackDataProto &)> Callback
void add_values(::operations_research::math_opt::BasisStatusProto value)
void add_ids(::int64_t value)
void add_ids(::int64_t value)
void add_values(double value)
bool AcceptsAndUpdate(int64_t id, const Value &value)
void InsertOrDie(Collection *const collection, const typename Collection::value_type &value)
std::string ValidateParameters(const GlopParameters ¶ms)
@ INFEASIBLE_OR_UNBOUNDED
std::string GetProblemStatusString(ProblemStatus problem_status)
TerminationProto TerminateForReason(const TerminationReasonProto reason, const absl::string_view detail)
SparseDoubleVectorProto FillSparseDoubleVector(absl::Span< const int64_t > ids_in_order, const absl::flat_hash_map< int64_t, IndexType > &id_map, const glop::StrictITIVector< IndexType, glop::Fractional > &values, const SparseVectorFilterProto &filter)
absl::Status ModelIsSupported(const ModelProto &model, const SupportedProblemStructures &support_menu, const absl::string_view solver_name)
@ TERMINATION_REASON_IMPRECISE
absl::Status ModelSolveParametersAreSupported(const ModelSolveParametersProto &model_parameters, const SupportedProblemStructures &support_menu, const absl::string_view solver_name)
int NumMatrixNonzeros(const SparseDoubleMatrixProto &matrix)
void UpdateIdIndexMap(glop::StrictITIVector< IndexType, bool > indices_to_delete, IndexType num_indices, absl::flat_hash_map< int64_t, IndexType > &id_index_map)
int NumVariables(const VariablesProto &variables)
@ LP_ALGORITHM_DUAL_SIMPLEX
@ LP_ALGORITHM_UNSPECIFIED
@ LP_ALGORITHM_PRIMAL_SIMPLEX
TerminationProto OptimalTerminationProto(const double finite_primal_objective, const double dual_objective, const absl::string_view detail)
@ FEASIBILITY_STATUS_FEASIBLE
@ FEASIBILITY_STATUS_UNDETERMINED
@ FEASIBILITY_STATUS_INFEASIBLE
TerminationProto InfeasibleOrUnboundedTerminationProto(bool is_maximize, const FeasibilityStatusProto dual_feasibility_status, const absl::string_view detail)
bool UpdateIsSupported(const ModelUpdateProto &update, const SupportedProblemStructures &support_menu)
BasisStatusProto FromGlopBasisStatus(const ValueType glop_basis_status)
ValueType ToGlopBasisStatus(const BasisStatusProto basis_status)
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)
glop::StrictITIVector< T, int64_t > IndexToId(const absl::flat_hash_map< int64_t, T > &id_map)
TerminationProto NoSolutionFoundTerminationProto(const bool is_maximize, const LimitProto limit, const std::optional< double > optional_dual_objective, const absl::string_view detail)
std::vector< int64_t > GetSortedIs(const absl::flat_hash_map< int64_t, T > &id_map)
absl::Status CheckRegisteredCallbackEvents(const CallbackRegistrationProto ®istration, const absl::flat_hash_set< CallbackEventProto > &supported_events)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
int NumConstraints(const LinearConstraintsProto &linear_constraints)
@ BASIS_STATUS_AT_UPPER_BOUND
@ BASIS_STATUS_FIXED_VALUE
@ BASIS_STATUS_UNSPECIFIED
@ BASIS_STATUS_AT_LOWER_BOUND
TerminationProto InfeasibleTerminationProto(bool is_maximize, const FeasibilityStatusProto dual_feasibility_status, const absl::string_view detail)
TerminationProto UnboundedTerminationProto(const bool is_maximize, const absl::string_view detail)
SparseBasisStatusVector FillSparseBasisStatusVector(absl::Span< const int64_t > ids_in_order, const absl::flat_hash_map< int64_t, IndexType > &id_map, const glop::StrictITIVector< IndexType, ValueType > &values)
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
std::string ProtoEnumToString(ProtoEnumType enum_value)
inline ::absl::StatusOr< absl::Duration > DecodeGoogleApiProto(const google::protobuf::Duration &proto)
inline ::absl::StatusOr< google::protobuf::Duration > EncodeGoogleApiProto(absl::Duration d)
StatusBuilder InvalidArgumentErrorBuilder()
#define MATH_OPT_REGISTER_SOLVER(solver_type, solver_factory)