24#include "absl/cleanup/cleanup.h"
25#include "absl/container/flat_hash_map.h"
26#include "absl/log/check.h"
27#include "absl/memory/memory.h"
28#include "absl/status/status.h"
29#include "absl/status/statusor.h"
30#include "absl/strings/str_cat.h"
31#include "absl/strings/str_join.h"
32#include "absl/strings/str_split.h"
33#include "absl/strings/string_view.h"
34#include "absl/time/clock.h"
35#include "absl/time/time.h"
36#include "absl/types/span.h"
43#include "ortools/glop/parameters.pb.h"
47#include "ortools/math_opt/callback.pb.h"
52#include "ortools/math_opt/infeasible_subsystem.pb.h"
53#include "ortools/math_opt/model.pb.h"
54#include "ortools/math_opt/model_parameters.pb.h"
55#include "ortools/math_opt/model_update.pb.h"
56#include "ortools/math_opt/parameters.pb.h"
57#include "ortools/math_opt/result.pb.h"
58#include "ortools/math_opt/solution.pb.h"
59#include "ortools/math_opt/sparse_containers.pb.h"
72constexpr SupportedProblemStructures kGlopSupportedStructures = {};
74absl::string_view SafeName(
const VariablesProto& variables,
int index) {
75 if (variables.names().empty()) {
78 return variables.names(
index);
81absl::string_view SafeName(
const LinearConstraintsProto& linear_constraints,
83 if (linear_constraints.names().empty()) {
86 return linear_constraints.names(
index);
89absl::StatusOr<TerminationProto> BuildTermination(
98 FEASIBILITY_STATUS_UNDETERMINED);
102 FEASIBILITY_STATUS_FEASIBLE);
108 FEASIBILITY_STATUS_INFEASIBLE);
112 FEASIBILITY_STATUS_UNDETERMINED);
120 is_maximize, interrupter !=
nullptr && interrupter->IsInterrupted()
122 : LIMIT_UNDETERMINED);
131 interrupter !=
nullptr && interrupter->IsInterrupted()
133 : LIMIT_UNDETERMINED,
143 interrupter !=
nullptr && interrupter->IsInterrupted()
145 : LIMIT_UNDETERMINED,
151 return absl::InternalError(
152 absl::StrCat(
"Unexpected GLOP termination reason: ",
155 LOG(FATAL) <<
"Unimplemented GLOP termination reason: "
160absl::Status ValidateGlopParameters(
const glop::GlopParameters&
parameters) {
162 if (!error.empty()) {
164 <<
"invalid GlopParameters: " << error;
166 return absl::OkStatus();
171GlopSolver::GlopSolver() : linear_program_(), lp_solver_() {}
173void GlopSolver::AddVariables(
const VariablesProto& variables) {
175 const glop::ColIndex col_index = linear_program_.CreateNewVariable();
176 linear_program_.SetVariableBounds(col_index, variables.lower_bounds(i),
177 variables.upper_bounds(i));
178 linear_program_.SetVariableName(col_index, SafeName(variables, i));
186template <
typename IndexType>
189 IndexType num_indices,
190 absl::flat_hash_map<int64_t, IndexType>& id_index_map) {
192 num_indices.value(), IndexType(0));
193 IndexType new_index(0);
195 if (indices_to_delete[
index]) {
197 new_indices[
index] = IndexType(-1);
199 new_indices[
index] = new_index;
203 for (
auto it = id_index_map.begin(); it != id_index_map.end();) {
204 IndexType
index = it->second;
205 if (indices_to_delete[
index]) {
207 id_index_map.erase(it++);
209 it->second = new_indices[
index];
215void GlopSolver::DeleteVariables(absl::Span<const int64_t> ids_to_delete) {
216 const glop::ColIndex num_cols = linear_program_.num_variables();
219 for (
const int64_t deleted_variable_id : ids_to_delete) {
220 columns_to_delete[variables_.at(deleted_variable_id)] =
true;
222 linear_program_.DeleteColumns(columns_to_delete);
223 UpdateIdIndexMap<glop::ColIndex>(columns_to_delete, num_cols, variables_);
226void GlopSolver::DeleteLinearConstraints(
227 absl::Span<const int64_t> ids_to_delete) {
228 const glop::RowIndex num_rows = linear_program_.num_constraints();
229 glop::DenseBooleanColumn rows_to_delete(num_rows,
false);
230 for (
const int64_t deleted_constraint_id : ids_to_delete) {
231 rows_to_delete[linear_constraints_.at(deleted_constraint_id)] =
true;
233 linear_program_.DeleteRows(rows_to_delete);
234 UpdateIdIndexMap<glop::RowIndex>(rows_to_delete, num_rows,
235 linear_constraints_);
238void GlopSolver::AddLinearConstraints(
239 const LinearConstraintsProto& linear_constraints) {
241 const glop::RowIndex row_index = linear_program_.CreateNewConstraint();
242 linear_program_.SetConstraintBounds(row_index,
243 linear_constraints.lower_bounds(i),
244 linear_constraints.upper_bounds(i));
245 linear_program_.SetConstraintName(row_index,
246 SafeName(linear_constraints, i));
252void GlopSolver::SetOrUpdateObjectiveCoefficients(
253 const SparseDoubleVectorProto& linear_objective_coefficients) {
254 for (
int i = 0;
i < linear_objective_coefficients.ids_size(); ++
i) {
255 const glop::ColIndex col_index =
256 variables_.at(linear_objective_coefficients.ids(i));
257 linear_program_.SetObjectiveCoefficient(
258 col_index, linear_objective_coefficients.values(i));
262void GlopSolver::SetOrUpdateConstraintMatrix(
263 const SparseDoubleMatrixProto& linear_constraint_matrix) {
265 const glop::ColIndex col_index =
266 variables_.at(linear_constraint_matrix.column_ids(j));
267 const glop::RowIndex row_index =
268 linear_constraints_.at(linear_constraint_matrix.row_ids(j));
269 const double coefficient = linear_constraint_matrix.coefficients(j);
270 linear_program_.SetCoefficient(row_index, col_index,
coefficient);
274void GlopSolver::UpdateVariableBounds(
275 const VariableUpdatesProto& variable_updates) {
276 for (
const auto [
id, lb] :
MakeView(variable_updates.lower_bounds())) {
277 const auto col_index = variables_.at(
id);
278 linear_program_.SetVariableBounds(
279 col_index, lb, linear_program_.variable_upper_bounds()[col_index]);
281 for (
const auto [
id, ub] :
MakeView(variable_updates.upper_bounds())) {
282 const auto col_index = variables_.at(
id);
283 linear_program_.SetVariableBounds(
284 col_index, linear_program_.variable_lower_bounds()[col_index], ub);
288void GlopSolver::UpdateLinearConstraintBounds(
289 const LinearConstraintUpdatesProto& linear_constraint_updates) {
290 for (
const auto [
id, lb] :
291 MakeView(linear_constraint_updates.lower_bounds())) {
292 const auto row_index = linear_constraints_.at(
id);
293 linear_program_.SetConstraintBounds(
294 row_index, lb, linear_program_.constraint_upper_bounds()[row_index]);
296 for (
const auto [
id, ub] :
297 MakeView(linear_constraint_updates.upper_bounds())) {
298 const auto row_index = linear_constraints_.at(
id);
299 linear_program_.SetConstraintBounds(
300 row_index, linear_program_.constraint_lower_bounds()[row_index], ub);
304absl::StatusOr<glop::GlopParameters> GlopSolver::MergeSolveParameters(
305 const SolveParametersProto& solve_parameters,
306 const bool setting_initial_basis,
const bool has_message_callback,
307 const bool is_maximization) {
310 <<
"invalid SolveParametersProto.glop value";
312 glop::GlopParameters result = solve_parameters.glop();
313 std::vector<std::string> warnings;
314 if (!result.has_max_time_in_seconds() && solve_parameters.has_time_limit()) {
317 result.set_max_time_in_seconds(absl::ToDoubleSeconds(
time_limit));
319 if (has_message_callback) {
323 result.set_log_search_progress(
true);
329 result.set_log_to_stdout(
false);
330 }
else if (!result.has_log_search_progress()) {
331 result.set_log_search_progress(solve_parameters.enable_output());
333 if (!result.has_num_omp_threads() && solve_parameters.has_threads()) {
334 result.set_num_omp_threads(solve_parameters.threads());
336 if (!result.has_random_seed() && solve_parameters.has_random_seed()) {
337 const int random_seed = std::max(0, solve_parameters.random_seed());
338 result.set_random_seed(random_seed);
340 if (!result.has_max_number_of_iterations() &&
341 solve_parameters.iteration_limit()) {
342 result.set_max_number_of_iterations(solve_parameters.iteration_limit());
344 if (solve_parameters.has_node_limit()) {
345 warnings.emplace_back(
"GLOP does snot support 'node_limit' parameter");
347 if (!result.has_use_dual_simplex() &&
348 solve_parameters.lp_algorithm() != LP_ALGORITHM_UNSPECIFIED) {
349 switch (solve_parameters.lp_algorithm()) {
350 case LP_ALGORITHM_PRIMAL_SIMPLEX:
351 result.set_use_dual_simplex(
false);
353 case LP_ALGORITHM_DUAL_SIMPLEX:
354 result.set_use_dual_simplex(
true);
357 warnings.emplace_back(absl::StrCat(
358 "GLOP does not support the 'lp_algorithm' parameter value: ",
362 if (!result.has_use_scaling() && !result.has_scaling_method() &&
363 solve_parameters.scaling() != EMPHASIS_UNSPECIFIED) {
364 switch (solve_parameters.scaling()) {
366 result.set_use_scaling(
false);
369 case EMPHASIS_MEDIUM:
371 case EMPHASIS_VERY_HIGH:
372 result.set_use_scaling(
true);
373 result.set_scaling_method(glop::GlopParameters::EQUILIBRATION);
376 LOG(FATAL) <<
"Scaling emphasis: "
378 <<
" unknown, error setting GLOP parameters";
381 if (setting_initial_basis) {
382 result.set_use_preprocessing(
false);
383 }
else if (!result.has_use_preprocessing() &&
384 solve_parameters.presolve() != EMPHASIS_UNSPECIFIED) {
385 switch (solve_parameters.presolve()) {
387 result.set_use_preprocessing(
false);
390 case EMPHASIS_MEDIUM:
392 case EMPHASIS_VERY_HIGH:
393 result.set_use_preprocessing(
true);
396 LOG(FATAL) <<
"Presolve emphasis: "
398 <<
" unknown, error setting GLOP parameters";
401 if (solve_parameters.cuts() != EMPHASIS_UNSPECIFIED) {
402 warnings.push_back(absl::StrCat(
403 "GLOP does not support 'cuts' parameters, but cuts was set to: ",
406 if (solve_parameters.heuristics() != EMPHASIS_UNSPECIFIED) {
408 absl::StrCat(
"GLOP does not support 'heuristics' parameter, but "
409 "heuristics was set to: ",
412 if (solve_parameters.has_cutoff_limit()) {
413 warnings.push_back(
"GLOP does not support 'cutoff_limit' parameter");
417 const auto set_upper_limit_if_missing = [&result](
const double limit) {
418 if (!result.has_objective_upper_limit()) {
419 result.set_objective_upper_limit(limit);
423 const auto set_lower_limit_if_missing = [&result](
const double limit) {
424 if (!result.has_objective_lower_limit()) {
425 result.set_objective_lower_limit(limit);
428 if (solve_parameters.has_objective_limit()) {
429 if (is_maximization) {
430 set_upper_limit_if_missing(solve_parameters.objective_limit());
432 set_lower_limit_if_missing(solve_parameters.objective_limit());
435 if (solve_parameters.has_best_bound_limit()) {
436 if (is_maximization) {
437 set_lower_limit_if_missing(solve_parameters.best_bound_limit());
439 set_upper_limit_if_missing(solve_parameters.best_bound_limit());
442 if (solve_parameters.has_solution_limit()) {
443 warnings.push_back(
"GLOP does not support 'solution_limit' parameter");
445 if (!warnings.empty()) {
446 return absl::InvalidArgumentError(absl::StrJoin(warnings,
"; "));
455 <<
"invalid GlopParameters generated from SolveParametersProto";
460template <
typename IndexType>
462 absl::Span<const int64_t> ids_in_order,
463 const absl::flat_hash_map<int64_t, IndexType>& id_map,
465 const SparseVectorFilterProto& filter) {
467 SparseDoubleVectorProto result;
468 for (
const int64_t variable_id : ids_in_order) {
469 const double value = values[id_map.at(variable_id)];
471 result.add_ids(variable_id);
472 result.add_values(
value);
479template <
typename ValueType>
481 switch (glop_basis_status) {
482 case ValueType::BASIC:
483 return BasisStatusProto::BASIS_STATUS_BASIC;
484 case ValueType::FIXED_VALUE:
485 return BasisStatusProto::BASIS_STATUS_FIXED_VALUE;
486 case ValueType::AT_LOWER_BOUND:
487 return BasisStatusProto::BASIS_STATUS_AT_LOWER_BOUND;
488 case ValueType::AT_UPPER_BOUND:
489 return BasisStatusProto::BASIS_STATUS_AT_UPPER_BOUND;
490 case ValueType::FREE:
491 return BasisStatusProto::BASIS_STATUS_FREE;
493 return BasisStatusProto::BASIS_STATUS_UNSPECIFIED;
496template <
typename IndexType,
typename ValueType>
498 absl::Span<const int64_t> ids_in_order,
499 const absl::flat_hash_map<int64_t, IndexType>& id_map,
501 SparseBasisStatusVector result;
502 for (
const int64_t variable_id : ids_in_order) {
503 const ValueType
value = values[id_map.at(variable_id)];
504 result.add_ids(variable_id);
511template <
typename ValueType>
513 switch (basis_status) {
514 case BASIS_STATUS_BASIC:
515 return ValueType::BASIC;
516 case BASIS_STATUS_FIXED_VALUE:
517 return ValueType::FIXED_VALUE;
518 case BASIS_STATUS_AT_LOWER_BOUND:
519 return ValueType::AT_LOWER_BOUND;
520 case BASIS_STATUS_AT_UPPER_BOUND:
521 return ValueType::AT_UPPER_BOUND;
522 case BASIS_STATUS_FREE:
523 return ValueType::FREE;
525 LOG(FATAL) <<
"Unexpected invalid initial_basis.";
526 return ValueType::FREE;
532 const absl::flat_hash_map<int64_t, T>& id_map) {
533 std::vector<int64_t> sorted;
534 sorted.reserve(id_map.size());
535 for (
const auto& entry : id_map) {
536 sorted.emplace_back(entry.first);
538 std::sort(sorted.begin(), sorted.end());
547 const absl::flat_hash_map<int64_t, T>& id_map) {
549 constexpr int64_t kEmptyId = -1;
551 for (
const auto& [
id,
index] : id_map) {
553 CHECK_EQ(index_to_id[
index], kEmptyId);
554 index_to_id[
index] = id;
564InvertedBounds GlopSolver::ListInvertedBounds()
const {
566 std::vector<glop::ColIndex> inverted_columns;
567 const glop::ColIndex num_cols = linear_program_.num_variables();
568 for (glop::ColIndex
col(0);
col < num_cols; ++
col) {
569 if (linear_program_.variable_lower_bounds()[
col] >
570 linear_program_.variable_upper_bounds()[
col]) {
571 inverted_columns.push_back(
col);
574 std::vector<glop::RowIndex> inverted_rows;
575 const glop::RowIndex num_rows = linear_program_.num_constraints();
576 for (glop::RowIndex
row(0);
row < num_rows; ++
row) {
577 if (linear_program_.constraint_lower_bounds()[
row] >
578 linear_program_.constraint_upper_bounds()[
row]) {
579 inverted_rows.push_back(
row);
585 InvertedBounds inverted_bounds;
586 if (!inverted_columns.empty()) {
587 const glop::StrictITIVector<glop::ColIndex, int64_t> ids =
589 CHECK_EQ(ids.size(), num_cols);
590 inverted_bounds.variables.reserve(inverted_columns.size());
591 for (
const glop::ColIndex
col : inverted_columns) {
592 inverted_bounds.variables.push_back(ids[
col]);
595 if (!inverted_rows.empty()) {
596 const glop::StrictITIVector<glop::RowIndex, int64_t> ids =
598 CHECK_EQ(ids.size(), num_rows);
599 inverted_bounds.linear_constraints.reserve(inverted_rows.size());
600 for (
const glop::RowIndex
row : inverted_rows) {
601 inverted_bounds.linear_constraints.push_back(ids[
row]);
605 return inverted_bounds;
608void GlopSolver::FillSolution(
const glop::ProblemStatus
status,
609 const ModelSolveParametersProto& model_parameters,
610 SolveResultProto& solve_result) {
615 const bool phase_I_solution_available =
616 (
status == glop::ProblemStatus::INIT) &&
617 (lp_solver_.GetNumberOfSimplexIterations() > 0);
618 if (
status != glop::ProblemStatus::OPTIMAL &&
619 status != glop::ProblemStatus::PRIMAL_FEASIBLE &&
620 status != glop::ProblemStatus::DUAL_FEASIBLE &&
621 status != glop::ProblemStatus::PRIMAL_UNBOUNDED &&
622 status != glop::ProblemStatus::DUAL_UNBOUNDED &&
623 !phase_I_solution_available) {
627 auto sorted_constraints =
GetSortedIs(linear_constraints_);
628 SolutionProto*
const solution = solve_result.add_solutions();
629 BasisProto*
const basis =
solution->mutable_basis();
631 solution->mutable_primal_solution();
632 DualSolutionProto*
const dual_solution =
solution->mutable_dual_solution();
637 if (
status == glop::ProblemStatus::OPTIMAL) {
639 basis->set_basic_dual_feasibility(SOLUTION_STATUS_FEASIBLE);
640 dual_solution->set_feasibility_status(SOLUTION_STATUS_FEASIBLE);
641 }
else if (
status == glop::ProblemStatus::PRIMAL_FEASIBLE) {
646 dual_solution->set_feasibility_status(SOLUTION_STATUS_UNDETERMINED);
647 basis->set_basic_dual_feasibility(SOLUTION_STATUS_INFEASIBLE);
648 }
else if (
status == glop::ProblemStatus::DUAL_FEASIBLE) {
655 dual_solution->set_feasibility_status(SOLUTION_STATUS_FEASIBLE);
656 basis->set_basic_dual_feasibility(SOLUTION_STATUS_FEASIBLE);
659 if (lp_solver_.GetParameters().use_dual_simplex()) {
664 dual_solution->set_feasibility_status(SOLUTION_STATUS_INFEASIBLE);
665 basis->set_basic_dual_feasibility(SOLUTION_STATUS_INFEASIBLE);
669 dual_solution->set_feasibility_status(SOLUTION_STATUS_UNDETERMINED);
670 basis->set_basic_dual_feasibility(SOLUTION_STATUS_UNDETERMINED);
676 if (basis->basic_dual_feasibility() == SOLUTION_STATUS_FEASIBLE) {
678 dual_solution->set_objective_value(
primal_solution->objective_value());
682 *basis->mutable_constraint_status() = *basis->mutable_variable_status() =
684 lp_solver_.variable_statuses());
685 *basis->mutable_constraint_status() =
687 lp_solver_.constraint_statuses());
690 sorted_variables, variables_, lp_solver_.variable_values(),
691 model_parameters.variable_values_filter());
694 sorted_constraints, linear_constraints_, lp_solver_.dual_values(),
695 model_parameters.dual_values_filter());
697 sorted_variables, variables_, lp_solver_.reduced_costs(),
698 model_parameters.reduced_costs_filter());
700 if (!lp_solver_.primal_ray().empty()) {
701 PrimalRayProto*
const primal_ray = solve_result.add_primal_rays();
704 sorted_variables, variables_, lp_solver_.primal_ray(),
705 model_parameters.variable_values_filter());
707 if (!lp_solver_.constraints_dual_ray().empty() &&
708 !lp_solver_.variable_bounds_dual_ray().empty()) {
709 DualRayProto*
const dual_ray = solve_result.add_dual_rays();
710 *dual_ray->mutable_dual_values() =
712 lp_solver_.constraints_dual_ray(),
713 model_parameters.dual_values_filter());
715 sorted_variables, variables_, lp_solver_.variable_bounds_dual_ray(),
716 model_parameters.reduced_costs_filter());
720absl::Status GlopSolver::FillSolveStats(
const absl::Duration solve_time,
721 SolveStatsProto& solve_stats) {
723 solve_stats.set_simplex_iterations(lp_solver_.GetNumberOfSimplexIterations());
725 solve_time, solve_stats.mutable_solve_time()));
727 return absl::OkStatus();
730absl::StatusOr<SolveResultProto> GlopSolver::MakeSolveResult(
731 const glop::ProblemStatus
status,
732 const ModelSolveParametersProto& model_parameters,
733 const SolveInterrupter*
const interrupter,
734 const absl::Duration solve_time) {
735 SolveResultProto solve_result;
737 BuildTermination(
status, interrupter,
738 linear_program_.IsMaximizationProblem(),
739 lp_solver_.GetObjectiveValue()));
740 FillSolution(
status, model_parameters, solve_result);
742 FillSolveStats(solve_time, *solve_result.mutable_solve_stats()));
746void GlopSolver::SetGlopBasis(
const BasisProto& basis) {
747 glop::VariableStatusRow variable_statuses(linear_program_.num_variables());
748 for (
const auto [
id,
value] :
MakeView(basis.variable_status())) {
749 variable_statuses[variables_.at(
id)] =
750 ToGlopBasisStatus<glop::VariableStatus>(
751 static_cast<BasisStatusProto
>(
value));
753 glop::ConstraintStatusColumn constraint_statuses(
754 linear_program_.num_constraints());
755 for (
const auto [
id,
value] :
MakeView(basis.constraint_status())) {
756 constraint_statuses[linear_constraints_.at(
id)] =
757 ToGlopBasisStatus<glop::ConstraintStatus>(
758 static_cast<BasisStatusProto
>(
value));
760 lp_solver_.SetInitialBasis(variable_statuses, constraint_statuses);
763absl::StatusOr<SolveResultProto> GlopSolver::Solve(
765 const ModelSolveParametersProto& model_parameters,
767 const CallbackRegistrationProto& callback_registration,
const Callback,
772 const absl::Time
start = absl::Now();
774 const glop::GlopParameters glop_parameters,
775 MergeSolveParameters(
777 model_parameters.has_initial_basis(),
778 message_cb !=
nullptr,
779 linear_program_.IsMaximizationProblem()));
780 lp_solver_.SetParameters(glop_parameters);
782 if (model_parameters.has_initial_basis()) {
783 SetGlopBasis(model_parameters.initial_basis());
786 std::atomic<bool> interrupt_solve =
false;
788 TimeLimit::FromParameters(lp_solver_.GetParameters());
789 time_limit->RegisterExternalBooleanAsLimit(&interrupt_solve);
792 CHECK_NE(interrupter,
nullptr);
793 interrupt_solve =
true;
796 if (message_cb !=
nullptr) {
804 CHECK_EQ(lp_solver_.GetSolverLogger().NumInfoLoggingCallbacks(), 0);
805 lp_solver_.GetSolverLogger().AddInfoLoggingCallback(
806 [&](absl::string_view
message) {
807 message_cb(absl::StrSplit(
message,
'\n'));
810 const auto message_cb_cleanup = absl::MakeCleanup([&]() {
811 if (message_cb !=
nullptr) {
813 CHECK_EQ(lp_solver_.GetSolverLogger().NumInfoLoggingCallbacks(), 1);
814 lp_solver_.GetSolverLogger().ClearInfoLoggingCallbacks();
824 lp_solver_.SolveWithTimeLimit(linear_program_,
time_limit.get());
825 const absl::Duration solve_time = absl::Now() -
start;
826 return MakeSolveResult(
status, model_parameters, interrupter, solve_time);
829absl::StatusOr<std::unique_ptr<SolverInterface>> GlopSolver::New(
832 auto solver = absl::WrapUnique(
new GlopSolver);
836 solver->linear_program_.SetDcheckBounds(
false);
838 solver->linear_program_.SetName(
model.name());
839 solver->linear_program_.SetMaximizationProblem(
model.objective().maximize());
840 solver->linear_program_.SetObjectiveOffset(
model.objective().offset());
842 solver->AddVariables(
model.variables());
843 solver->SetOrUpdateObjectiveCoefficients(
844 model.objective().linear_coefficients());
846 solver->AddLinearConstraints(
model.linear_constraints());
847 solver->SetOrUpdateConstraintMatrix(
model.linear_constraint_matrix());
848 solver->linear_program_.CleanUp();
852absl::StatusOr<bool> GlopSolver::Update(
const ModelUpdateProto& model_update) {
857 if (model_update.objective_updates().has_direction_update()) {
858 linear_program_.SetMaximizationProblem(
859 model_update.objective_updates().direction_update());
861 if (model_update.objective_updates().has_offset_update()) {
862 linear_program_.SetObjectiveOffset(
863 model_update.objective_updates().offset_update());
866 DeleteVariables(model_update.deleted_variable_ids());
867 AddVariables(model_update.new_variables());
869 SetOrUpdateObjectiveCoefficients(
870 model_update.objective_updates().linear_coefficients());
871 UpdateVariableBounds(model_update.variable_updates());
873 DeleteLinearConstraints(model_update.deleted_linear_constraint_ids());
874 AddLinearConstraints(model_update.new_linear_constraints());
875 UpdateLinearConstraintBounds(model_update.linear_constraint_updates());
877 SetOrUpdateConstraintMatrix(model_update.linear_constraint_matrix_updates());
879 linear_program_.CleanUp();
884absl::StatusOr<ComputeInfeasibleSubsystemResultProto>
885GlopSolver::ComputeInfeasibleSubsystem(
const SolveParametersProto&,
888 return absl::UnimplementedError(
889 "GLOP does not implement a method to compute an infeasible subsystem");
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
std::function< void(const std::vector< std::string > &)> MessageCallback
std::function< absl::StatusOr< CallbackResultProto >( const CallbackDataProto &)> Callback
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)
ProblemStatus
Different statuses for a given problem.
@ INFEASIBLE_OR_UNBOUNDED
@ ABNORMAL
An error occurred during the solving process.
@ INVALID_PROBLEM
The input problem was invalid (see LinearProgram.IsValid()).
@ INIT
The solver didn't had a chance to prove anything.
std::string GetProblemStatusString(ProblemStatus problem_status)
Returns the string representation of the ProblemStatus enum.
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)
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)
TerminationProto OptimalTerminationProto(const double finite_primal_objective, const double 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)
BasisStatusProto FromGlopBasisStatus(const ValueType glop_basis_status)
ValueType should be glop's VariableStatus or ConstraintStatus.
ValueType ToGlopBasisStatus(const BasisStatusProto basis_status)
ValueType should be glop's VariableStatus or ConstraintStatus.
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)
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)
In SWIG mode, we don't want anything besides these top-level includes.
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)
Initialization arguments.
double objective_value
The value objective_vector^T * (solution - center_point).