20 #include "absl/memory/memory.h"
21 #include "absl/strings/match.h"
22 #include "absl/strings/str_format.h"
34 #ifndef __PORTABLE_PLATFORM__
38 ABSL_FLAG(
bool, lp_solver_enable_fp_exceptions,
false,
39 "When true, NaNs and division / zero produce errors. "
40 "This is very useful for debugging, but incompatible with LLVM. "
41 "It is recommended to set this to false for production usage.");
43 "Tells whether do dump the problem to a protobuf file.");
45 "Whether the proto dump file is compressed.");
47 "Whether the proto dump file is binary.");
49 "Number for the dump file, in the form name-000048.pb. "
50 "If < 0, the file is automatically numbered from the number of "
51 "calls to LPSolver::Solve().");
53 "Directory where dump files are written.");
55 "Base name for dump files. LinearProgram::name_ is used if "
56 "lp_dump_file_basename is empty. If LinearProgram::name_ is "
57 "empty, \"linear_program_dump_file\" is used.");
59 "Override any user parameters with the value of this flag. This is "
60 "interpreted as a GlopParameters proto in text format.");
73 void DumpLinearProgramIfRequiredByFlags(
const LinearProgram& linear_program,
75 if (!absl::GetFlag(FLAGS_lp_dump_to_proto_file))
return;
76 #ifdef __PORTABLE_PLATFORM__
77 LOG(
WARNING) <<
"DumpLinearProgramIfRequiredByFlags(linear_program, num) "
78 "requested for linear_program.name()='"
79 << linear_program.name() <<
"', num=" << num
80 <<
" but is not implemented for this platform.";
82 std::string filename = absl::GetFlag(FLAGS_lp_dump_file_basename);
83 if (filename.empty()) {
84 if (linear_program.name().empty()) {
85 filename =
"linear_program_dump";
87 filename = linear_program.name();
90 const int file_num = absl::GetFlag(FLAGS_lp_dump_file_number) >= 0
91 ? absl::GetFlag(FLAGS_lp_dump_file_number)
93 absl::StrAppendFormat(&filename,
"-%06d.pb", file_num);
94 const std::string filespec =
95 absl::StrCat(absl::GetFlag(FLAGS_lp_dump_dir),
"/", filename);
98 const ProtoWriteFormat write_format = absl::GetFlag(FLAGS_lp_dump_binary_file)
102 absl::GetFlag(FLAGS_lp_dump_compressed_file))) {
103 LOG(DFATAL) <<
"Could not write " << filespec;
118 #ifndef __PORTABLE_PLATFORM__
119 if (!absl::GetFlag(FLAGS_glop_params).empty()) {
120 GlopParameters flag_params;
121 CHECK(google::protobuf::TextFormat::ParseFromString(
122 absl::GetFlag(FLAGS_glop_params), &flag_params));
123 parameters_.MergeFrom(flag_params);
141 LOG(DFATAL) <<
"SolveWithTimeLimit() called with a nullptr time_limit.";
145 num_revised_simplex_iterations_ = 0;
146 DumpLinearProgramIfRequiredByFlags(lp, num_solves_);
149 LOG(DFATAL) <<
"The columns of the given linear program should be ordered "
150 <<
"by row and contain no zero coefficients. Call CleanUp() "
151 <<
"on it before calling Solve().";
156 LOG(DFATAL) <<
"The given linear program is invalid. It contains NaNs, "
157 <<
"infinite coefficients or invalid bounds specification. "
158 <<
"You can construct it in debug mode to get the exact cause.";
164 <<
"\n******************************************************************"
165 "\n* WARNING: Glop will be very slow because it will use DCHECKs *"
166 "\n* to verify the results and the precision of the solver. *"
167 "\n* You can gain at least an order of magnitude speedup by *"
168 "\n* compiling with optimizations enabled and by defining NDEBUG. *"
169 "\n******************************************************************";
175 if (absl::GetFlag(FLAGS_lp_solver_enable_fp_exceptions)) {
184 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
196 const bool postsolve_is_needed = preprocessor.
Run(¤t_linear_program_);
199 LOG(
INFO) <<
"Presolved problem: "
201 LOG(
INFO) <<
"Objective stats: "
217 RunRevisedSimplexIfNeeded(&solution,
time_limit);
225 LOG(
INFO) <<
"status: " << status;
229 LOG(
INFO) <<
"deterministic_time: "
237 ResizeSolution(RowIndex(0), ColIndex(0));
238 revised_simplex_.reset(
nullptr);
268 if (revised_simplex_ ==
nullptr) {
269 revised_simplex_ = absl::make_unique<RevisedSimplex>();
271 revised_simplex_->LoadStateForNextSolve(state);
272 if (parameters_.use_preprocessing()) {
273 LOG(
WARNING) <<
"In GLOP, SetInitialBasis() was called but the parameter "
274 "use_preprocessing is true, this will likely not result in "
297 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
299 if (!IsProblemSolutionConsistent(lp, solution)) {
300 if (log_info)
LOG(
INFO) <<
"Inconsistency detected in the solution.";
314 ComputeReducedCosts(lp);
315 const Fractional primal_objective_value = ComputeObjective(lp);
316 const Fractional dual_objective_value = ComputeDualObjective(lp);
318 LOG(
INFO) <<
"Primal objective (before moving primal/dual values) = "
319 << absl::StrFormat(
"%.15E", ProblemObjectiveValue(
320 lp, primal_objective_value));
321 LOG(
INFO) <<
"Dual objective (before moving primal/dual values) = "
323 "%.15E", ProblemObjectiveValue(lp, dual_objective_value));
328 parameters_.provide_strong_optimal_guarantee()) {
329 MovePrimalValuesWithinBounds(lp);
330 MoveDualValuesWithinBounds(lp);
334 problem_objective_value_ = ProblemObjectiveValue(lp, ComputeObjective(lp));
336 LOG(
INFO) <<
"Primal objective (after moving primal/dual values) = "
337 << absl::StrFormat(
"%.15E", problem_objective_value_);
340 ComputeReducedCosts(lp);
341 ComputeConstraintActivities(lp);
351 bool rhs_perturbation_is_too_large =
false;
352 bool cost_perturbation_is_too_large =
false;
353 bool primal_infeasibility_is_too_large =
false;
354 bool dual_infeasibility_is_too_large =
false;
355 bool primal_residual_is_too_large =
false;
356 bool dual_residual_is_too_large =
false;
359 ComputeMaxRhsPerturbationToEnforceOptimality(lp,
360 &rhs_perturbation_is_too_large);
361 ComputeMaxCostPerturbationToEnforceOptimality(
362 lp, &cost_perturbation_is_too_large);
363 const double primal_infeasibility =
364 ComputePrimalValueInfeasibility(lp, &primal_infeasibility_is_too_large);
365 const double dual_infeasibility =
366 ComputeDualValueInfeasibility(lp, &dual_infeasibility_is_too_large);
367 const double primal_residual =
368 ComputeActivityInfeasibility(lp, &primal_residual_is_too_large);
369 const double dual_residual =
370 ComputeReducedCostInfeasibility(lp, &dual_residual_is_too_large);
375 max_absolute_primal_infeasibility_ =
376 std::max(primal_infeasibility, primal_residual);
377 max_absolute_dual_infeasibility_ =
378 std::max(dual_infeasibility, dual_residual);
380 LOG(
INFO) <<
"Max. primal infeasibility = "
381 << max_absolute_primal_infeasibility_;
382 LOG(
INFO) <<
"Max. dual infeasibility = "
383 << max_absolute_dual_infeasibility_;
389 const double objective_error_ub = ComputeMaxExpectedObjectiveError(lp);
391 LOG(
INFO) <<
"Objective error <= " << objective_error_ub;
395 parameters_.provide_strong_optimal_guarantee()) {
398 if (primal_infeasibility != 0.0 || dual_infeasibility != 0.0) {
399 LOG(
ERROR) <<
"Primal/dual values have been moved to their bounds. "
400 <<
"Therefore the primal/dual infeasibilities should be "
401 <<
"exactly zero (but not the residuals). If this message "
402 <<
"appears, there is probably a bug in "
403 <<
"MovePrimalValuesWithinBounds() or in "
404 <<
"MoveDualValuesWithinBounds().";
406 if (rhs_perturbation_is_too_large) {
407 if (log_info)
LOG(
INFO) <<
"The needed rhs perturbation is too large !!";
410 if (cost_perturbation_is_too_large) {
411 if (log_info)
LOG(
INFO) <<
"The needed cost perturbation is too large !!";
420 if (std::abs(primal_objective_value - dual_objective_value) >
421 objective_error_ub) {
423 LOG(
INFO) <<
"The objective gap of the final solution is too large.";
430 (primal_residual_is_too_large || primal_infeasibility_is_too_large)) {
433 <<
"The primal infeasibility of the final solution is too large.";
439 (dual_residual_is_too_large || dual_infeasibility_is_too_large)) {
441 LOG(
INFO) <<
"The dual infeasibility of the final solution is too large.";
446 may_have_multiple_solutions_ =
451 bool LPSolver::IsOptimalSolutionOnFacet(
const LinearProgram& lp) {
456 const double kReducedCostTolerance = 1e-9;
457 const double kBoundTolerance = 1e-7;
459 for (ColIndex
col(0);
col < num_cols; ++
col) {
465 kReducedCostTolerance) &&
472 for (RowIndex
row(0);
row < num_rows; ++
row) {
478 kReducedCostTolerance) &&
488 return problem_objective_value_;
492 return max_absolute_primal_infeasibility_;
496 return max_absolute_dual_infeasibility_;
500 return may_have_multiple_solutions_;
504 return num_revised_simplex_iterations_;
508 return revised_simplex_ ==
nullptr ? 0.0
509 : revised_simplex_->DeterministicTime();
512 void LPSolver::MovePrimalValuesWithinBounds(
const LinearProgram& lp) {
516 for (ColIndex
col(0);
col < num_cols; ++
col) {
526 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
527 if (log_info)
LOG(
INFO) <<
"Max. primal values move = " << error;
530 void LPSolver::MoveDualValuesWithinBounds(
const LinearProgram& lp) {
531 const RowIndex num_rows = lp.num_constraints();
533 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
535 for (RowIndex
row(0);
row < num_rows; ++
row) {
540 Fractional minimization_dual_value = optimization_sign * dual_values_[
row];
542 error =
std::max(error, minimization_dual_value);
543 minimization_dual_value = 0.0;
546 error =
std::max(error, -minimization_dual_value);
547 minimization_dual_value = 0.0;
549 dual_values_[
row] = optimization_sign * minimization_dual_value;
551 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
552 if (log_info)
LOG(
INFO) <<
"Max. dual values move = " << error;
555 void LPSolver::ResizeSolution(RowIndex num_rows, ColIndex num_cols) {
556 primal_values_.
resize(num_cols, 0.0);
557 reduced_costs_.
resize(num_cols, 0.0);
560 dual_values_.resize(num_rows, 0.0);
561 constraint_activities_.
resize(num_rows, 0.0);
565 void LPSolver::RunRevisedSimplexIfNeeded(ProblemSolution* solution,
576 if (revised_simplex_ ==
nullptr) {
577 revised_simplex_ = absl::make_unique<RevisedSimplex>();
579 revised_simplex_->SetParameters(parameters_);
580 if (revised_simplex_->Solve(current_linear_program_,
time_limit).ok()) {
581 num_revised_simplex_iterations_ = revised_simplex_->GetNumberOfIterations();
582 solution->status = revised_simplex_->GetProblemStatus();
584 const ColIndex num_cols = revised_simplex_->GetProblemNumCols();
585 DCHECK_EQ(solution->primal_values.size(), num_cols);
586 for (ColIndex
col(0);
col < num_cols; ++
col) {
587 solution->primal_values[
col] = revised_simplex_->GetVariableValue(
col);
588 solution->variable_statuses[
col] =
589 revised_simplex_->GetVariableStatus(
col);
592 const RowIndex num_rows = revised_simplex_->GetProblemNumRows();
593 DCHECK_EQ(solution->dual_values.size(), num_rows);
594 for (RowIndex
row(0);
row < num_rows; ++
row) {
595 solution->dual_values[
row] = revised_simplex_->GetDualValue(
row);
596 solution->constraint_statuses[
row] =
597 revised_simplex_->GetConstraintStatus(
row);
600 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
601 if (log_info)
LOG(
INFO) <<
"Error during the revised simplex algorithm.";
611 VLOG(1) <<
"Variable " <<
col <<
" status is "
613 <<
" and its bounds are [" << lb <<
", " << ub <<
"].";
618 VLOG(1) <<
"Constraint " <<
row <<
" status is "
620 <<
", " << ub <<
"].";
625 bool LPSolver::IsProblemSolutionConsistent(
626 const LinearProgram& lp,
const ProblemSolution& solution)
const {
627 const RowIndex num_rows = lp.num_constraints();
628 const ColIndex num_cols = lp.num_variables();
629 if (solution.variable_statuses.size() != num_cols)
return false;
630 if (solution.constraint_statuses.size() != num_rows)
return false;
631 if (solution.primal_values.size() != num_cols)
return false;
632 if (solution.dual_values.size() != num_rows)
return false;
641 RowIndex num_basic_variables(0);
642 for (ColIndex
col(0);
col < num_cols; ++
col) {
647 switch (solution.variable_statuses[
col]) {
651 ++num_basic_variables;
664 LogVariableStatusError(
col,
value, status, lb, ub);
669 if (
value != lb || lb == ub) {
670 LogVariableStatusError(
col,
value, status, lb, ub);
678 LogVariableStatusError(
col,
value, status, lb, ub);
684 LogVariableStatusError(
col,
value, status, lb, ub);
690 for (RowIndex
row(0);
row < num_rows; ++
row) {
701 if (dual_value != 0.0) {
702 VLOG(1) <<
"Constraint " <<
row <<
" is BASIC, but its dual value is "
703 << dual_value <<
" instead of 0.";
706 ++num_basic_variables;
712 if (ub - lb > 1e-12) {
713 LogConstraintStatusError(
row, status, lb, ub);
719 LogConstraintStatusError(
row, status, lb, ub);
725 LogConstraintStatusError(
row, status, lb, ub);
730 if (dual_value != 0.0) {
731 VLOG(1) <<
"Constraint " <<
row <<
" is FREE, but its dual value is "
732 << dual_value <<
" instead of 0.";
736 LogConstraintStatusError(
row, status, lb, ub);
745 if (num_basic_variables != num_rows) {
746 VLOG(1) <<
"Wrong number of basic variables: " << num_basic_variables;
756 Fractional LPSolver::ComputeMaxCostPerturbationToEnforceOptimality(
757 const LinearProgram& lp,
bool* is_too_large) {
759 const ColIndex num_cols = lp.num_variables();
760 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
761 const Fractional tolerance = parameters_.solution_feasibility_tolerance();
762 for (ColIndex
col(0);
col < num_cols; ++
col) {
766 const Fractional reduced_cost = optimization_sign * reduced_costs_[
col];
771 max_cost_correction =
772 std::max(max_cost_correction, std::abs(reduced_cost));
774 std::abs(reduced_cost) >
775 AllowedError(tolerance, lp.objective_coefficients()[
col]);
778 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
779 if (log_info)
LOG(
INFO) <<
"Max. cost perturbation = " << max_cost_correction;
780 return max_cost_correction;
785 Fractional LPSolver::ComputeMaxRhsPerturbationToEnforceOptimality(
786 const LinearProgram& lp,
bool* is_too_large) {
788 const RowIndex num_rows = lp.num_constraints();
789 const Fractional tolerance = parameters_.solution_feasibility_tolerance();
790 for (RowIndex
row(0);
row < num_rows; ++
row) {
800 allowed_error = AllowedError(tolerance,
lower_bound);
804 allowed_error = AllowedError(tolerance,
upper_bound);
806 max_rhs_correction =
std::max(max_rhs_correction, rhs_error);
807 *is_too_large |= rhs_error > allowed_error;
809 const bool log_info = parameters_.log_search_progress() ||
VLOG_IS_ON(1);
810 if (log_info)
LOG(
INFO) <<
"Max. rhs perturbation = " << max_rhs_correction;
811 return max_rhs_correction;
814 void LPSolver::ComputeConstraintActivities(
const LinearProgram& lp) {
815 const RowIndex num_rows = lp.num_constraints();
816 const ColIndex num_cols = lp.num_variables();
818 constraint_activities_.
assign(num_rows, 0.0);
819 for (ColIndex
col(0);
col < num_cols; ++
col) {
820 lp.GetSparseColumn(
col).AddMultipleToDenseVector(primal_values_[
col],
821 &constraint_activities_);
825 void LPSolver::ComputeReducedCosts(
const LinearProgram& lp) {
826 const RowIndex num_rows = lp.num_constraints();
827 const ColIndex num_cols = lp.num_variables();
828 DCHECK_EQ(num_rows, dual_values_.size());
829 reduced_costs_.resize(num_cols, 0.0);
830 for (ColIndex
col(0);
col < num_cols; ++
col) {
831 reduced_costs_[
col] = lp.objective_coefficients()[
col] -
836 double LPSolver::ComputeObjective(
const LinearProgram& lp) {
837 const ColIndex num_cols = lp.num_variables();
840 for (ColIndex
col(0);
col < num_cols; ++
col) {
841 sum.
Add(lp.objective_coefficients()[
col] * primal_values_[
col]);
862 double LPSolver::ComputeDualObjective(
const LinearProgram& lp) {
866 const RowIndex num_rows = lp.num_constraints();
867 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
868 for (RowIndex
row(0);
row < num_rows; ++
row) {
873 const Fractional corrected_value = optimization_sign * dual_values_[
row];
898 const ColIndex num_cols = lp.num_variables();
899 for (ColIndex
col(0);
col < num_cols; ++
col) {
905 const Fractional reduced_cost = optimization_sign * reduced_costs_[
col];
911 reduced_cost > 0.0) {
914 reduced_cost < 0.0) {
920 dual_objective.Add(optimization_sign * correction);
922 return dual_objective.Value();
925 double LPSolver::ComputeMaxExpectedObjectiveError(
const LinearProgram& lp) {
926 const ColIndex num_cols = lp.num_variables();
928 const Fractional tolerance = parameters_.solution_feasibility_tolerance();
930 for (ColIndex
col(0);
col < num_cols; ++
col) {
934 primal_objective_error += std::abs(lp.objective_coefficients()[
col]) *
935 AllowedError(tolerance, primal_values_[
col]);
937 return primal_objective_error;
940 double LPSolver::ComputePrimalValueInfeasibility(
const LinearProgram& lp,
941 bool* is_too_large) {
942 double infeasibility = 0.0;
943 const Fractional tolerance = parameters_.solution_feasibility_tolerance();
944 const ColIndex num_cols = lp.num_variables();
945 for (ColIndex
col(0);
col < num_cols; ++
col) {
952 infeasibility =
std::max(infeasibility, error);
953 *is_too_large |= error > AllowedError(tolerance,
upper_bound);
958 infeasibility =
std::max(infeasibility, error);
959 *is_too_large |= error > AllowedError(tolerance,
upper_bound);
963 infeasibility =
std::max(infeasibility, error);
964 *is_too_large |= error > AllowedError(tolerance,
lower_bound);
967 return infeasibility;
970 double LPSolver::ComputeActivityInfeasibility(
const LinearProgram& lp,
971 bool* is_too_large) {
972 double infeasibility = 0.0;
973 int num_problematic_rows(0);
974 const RowIndex num_rows = lp.num_constraints();
975 const Fractional tolerance = parameters_.solution_feasibility_tolerance();
976 for (RowIndex
row(0);
row < num_rows; ++
row) {
985 VLOG(2) <<
"Row " <<
row.value() <<
" has activity " << activity
986 <<
" which is different from " <<
upper_bound <<
" by "
988 ++num_problematic_rows;
995 if (row_excess > AllowedError(tolerance,
upper_bound)) {
996 VLOG(2) <<
"Row " <<
row.value() <<
" has activity " << activity
997 <<
", exceeding its upper bound " <<
upper_bound <<
" by "
999 ++num_problematic_rows;
1001 infeasibility =
std::max(infeasibility, row_excess);
1005 if (row_deficit > AllowedError(tolerance,
lower_bound)) {
1006 VLOG(2) <<
"Row " <<
row.value() <<
" has activity " << activity
1007 <<
", below its lower bound " <<
lower_bound <<
" by "
1009 ++num_problematic_rows;
1011 infeasibility =
std::max(infeasibility, row_deficit);
1014 if (num_problematic_rows > 0) {
1015 *is_too_large =
true;
1016 VLOG(1) <<
"Number of infeasible rows = " << num_problematic_rows;
1018 return infeasibility;
1021 double LPSolver::ComputeDualValueInfeasibility(
const LinearProgram& lp,
1022 bool* is_too_large) {
1023 const Fractional allowed_error = parameters_.solution_feasibility_tolerance();
1024 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
1025 double infeasibility = 0.0;
1026 const RowIndex num_rows = lp.num_constraints();
1027 for (RowIndex
row(0);
row < num_rows; ++
row) {
1032 const Fractional minimization_dual_value = optimization_sign * dual_value;
1034 *is_too_large |= minimization_dual_value > allowed_error;
1035 infeasibility =
std::max(infeasibility, minimization_dual_value);
1038 *is_too_large |= -minimization_dual_value > allowed_error;
1039 infeasibility =
std::max(infeasibility, -minimization_dual_value);
1042 return infeasibility;
1045 double LPSolver::ComputeReducedCostInfeasibility(
const LinearProgram& lp,
1046 bool* is_too_large) {
1047 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
1048 double infeasibility = 0.0;
1049 const ColIndex num_cols = lp.num_variables();
1050 const Fractional tolerance = parameters_.solution_feasibility_tolerance();
1051 for (ColIndex
col(0);
col < num_cols; ++
col) {
1057 optimization_sign * reduced_cost;
1059 AllowedError(tolerance, lp.objective_coefficients()[
col]);
1061 *is_too_large |= minimization_reduced_cost > allowed_error;
1062 infeasibility =
std::max(infeasibility, minimization_reduced_cost);
1065 *is_too_large |= -minimization_reduced_cost > allowed_error;
1066 infeasibility =
std::max(infeasibility, -minimization_reduced_cost);
1069 return infeasibility;
#define DCHECK_LE(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
void push_back(const value_type &x)
void Add(const FpNumber &value)
void EnableExceptions(int excepts)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
static std::unique_ptr< TimeLimit > FromParameters(const Parameters ¶meters)
Creates a time limit object initialized from an object that provides methods max_time_in_seconds() an...
const GlopParameters & GetParameters() const
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
const ConstraintStatusColumn & constraint_statuses() const
bool MayHaveMultipleOptimalSolutions() const
const VariableStatusRow & variable_statuses() const
GlopParameters * GetMutableParameters()
Fractional GetMaximumDualInfeasibility() const
Fractional GetMaximumPrimalInfeasibility() const
Fractional GetObjectiveValue() const
ProblemStatus LoadAndVerifySolution(const LinearProgram &lp, const ProblemSolution &solution)
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
void SetParameters(const GlopParameters ¶meters)
double DeterministicTime() const
int GetNumberOfSimplexIterations() const
std::string GetObjectiveStatsString() const
void PopulateFromLinearProgram(const LinearProgram &linear_program)
void ClearTransposeMatrix()
const DenseRow & variable_lower_bounds() const
const DenseColumn & constraint_lower_bounds() const
std::string GetBoundsStatsString() const
Fractional objective_offset() const
const DenseColumn & constraint_upper_bounds() const
const DenseRow & variable_upper_bounds() const
ColIndex num_variables() const
std::string GetDimensionString() const
Fractional objective_scaling_factor() const
RowIndex num_constraints() const
void RecoverSolution(ProblemSolution *solution) const override
bool Run(LinearProgram *lp) final
ProblemStatus status() const
void SetTimeLimit(TimeLimit *time_limit)
void resize(IntType size)
void assign(IntType size, const T &v)
SharedTimeLimit * time_limit
ABSL_FLAG(bool, lp_solver_enable_fp_exceptions, false, "When true, NaNs and division / zero produce errors. " "This is very useful for debugging, but incompatible with LLVM. " "It is recommended to set this to false for production usage.")
AccurateSum< Fractional > KahanSum
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
std::string GetConstraintStatusString(ConstraintStatus status)
void LinearProgramToMPModelProto(const LinearProgram &input, MPModelProto *output)
bool IsFinite(Fractional value)
std::string GetVariableStatusString(VariableStatus status)
Collection of objects used to extend the Constraint Solver library.
bool WriteProtoToFile(absl::string_view filename, const google::protobuf::Message &proto, ProtoWriteFormat proto_write_format, bool gzipped, bool append_extension_to_file_name)
bool AreWithinAbsoluteTolerance(FloatType x, FloatType y, FloatType absolute_tolerance)
VariableStatusRow statuses
VariableStatusRow variable_statuses
ConstraintStatusColumn constraint_statuses
#define VLOG_IS_ON(verboselevel)