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_dump_to_proto_file,
false,
39 "Tells whether do dump the problem to a protobuf file.");
40 ABSL_FLAG(
bool, lp_dump_compressed_file,
true,
41 "Whether the proto dump file is compressed.");
42 ABSL_FLAG(
bool, lp_dump_binary_file,
false,
43 "Whether the proto dump file is binary.");
45 "Number for the dump file, in the form name-000048.pb. " 46 "If < 0, the file is automatically numbered from the number of " 47 "calls to LPSolver::Solve().");
48 ABSL_FLAG(std::string, lp_dump_dir,
"/tmp",
49 "Directory where dump files are written.");
50 ABSL_FLAG(std::string, lp_dump_file_basename,
"",
51 "Base name for dump files. LinearProgram::name_ is used if " 52 "lp_dump_file_basename is empty. If LinearProgram::name_ is " 53 "empty, \"linear_program_dump_file\" is used.");
55 "Override any user parameters with the value of this flag. This is " 56 "interpreted as a GlopParameters proto in text format.");
69 void DumpLinearProgramIfRequiredByFlags(
const LinearProgram& linear_program,
71 if (!absl::GetFlag(FLAGS_lp_dump_to_proto_file))
return;
72 #ifdef __PORTABLE_PLATFORM__ 73 LOG(
WARNING) <<
"DumpLinearProgramIfRequiredByFlags(linear_program, num) " 74 "requested for linear_program.name()='" 75 << linear_program.name() <<
"', num=" << num
76 <<
" but is not implemented for this platform.";
78 std::string filename = absl::GetFlag(FLAGS_lp_dump_file_basename);
79 if (filename.empty()) {
80 if (linear_program.name().empty()) {
81 filename =
"linear_program_dump";
83 filename = linear_program.name();
86 const int file_num = absl::GetFlag(FLAGS_lp_dump_file_number) >= 0
87 ? absl::GetFlag(FLAGS_lp_dump_file_number)
89 absl::StrAppendFormat(&filename,
"-%06d.pb", file_num);
90 const std::string filespec =
91 absl::StrCat(absl::GetFlag(FLAGS_lp_dump_dir),
"/", filename);
94 const ProtoWriteFormat write_format = absl::GetFlag(FLAGS_lp_dump_binary_file)
98 absl::GetFlag(FLAGS_lp_dump_compressed_file))) {
99 LOG(DFATAL) <<
"Could not write " << filespec;
114 #ifndef __PORTABLE_PLATFORM__ 115 if (!absl::GetFlag(FLAGS_glop_params).empty()) {
117 CHECK(google::protobuf::TextFormat::ParseFromString(
118 absl::GetFlag(FLAGS_glop_params), &flag_params));
139 LOG(DFATAL) <<
"SolveWithTimeLimit() called with a nullptr time_limit.";
143 num_revised_simplex_iterations_ = 0;
144 DumpLinearProgramIfRequiredByFlags(lp, num_solves_);
148 LOG(DFATAL) <<
"The columns of the given linear program should be ordered " 149 <<
"by row and contain no zero coefficients. Call CleanUp() " 150 <<
"on it before calling Solve().";
155 LOG(DFATAL) <<
"The given linear program is invalid. It contains NaNs, " 156 <<
"infinite coefficients or invalid bounds specification. " 157 <<
"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******************************************************************";
193 const bool postsolve_is_needed = preprocessor.
Run(¤t_linear_program_);
215 RunRevisedSimplexIfNeeded(&solution,
time_limit);
234 ResizeSolution(RowIndex(0), ColIndex(0));
235 revised_simplex_.reset(
nullptr);
265 if (revised_simplex_ ==
nullptr) {
266 revised_simplex_ = absl::make_unique<RevisedSimplex>();
267 revised_simplex_->SetLogger(&logger_);
269 revised_simplex_->LoadStateForNextSolve(state);
271 LOG(
WARNING) <<
"In GLOP, SetInitialBasis() was called but the parameter " 272 "use_preprocessing is true, this will likely not result in " 296 SOLVER_LOG(&logger_,
"Final unscaled solution:");
298 if (!IsProblemSolutionConsistent(lp, solution)) {
299 SOLVER_LOG(&logger_,
"Inconsistency detected in the solution.");
314 ComputeReducedCosts(lp);
315 const Fractional primal_objective_value = ComputeObjective(lp);
316 const Fractional dual_objective_value = ComputeDualObjective(lp);
317 SOLVER_LOG(&logger_,
"Primal objective (before moving primal/dual values) = ",
319 "%.15E", ProblemObjectiveValue(lp, primal_objective_value)));
320 SOLVER_LOG(&logger_,
"Dual objective (before moving primal/dual values) = ",
321 absl::StrFormat(
"%.15E",
322 ProblemObjectiveValue(lp, dual_objective_value)));
327 MovePrimalValuesWithinBounds(lp);
328 MoveDualValuesWithinBounds(lp);
332 problem_objective_value_ = ProblemObjectiveValue(lp, ComputeObjective(lp));
333 SOLVER_LOG(&logger_,
"Primal objective (after moving primal/dual values) = ",
334 absl::StrFormat(
"%.15E", problem_objective_value_));
336 ComputeReducedCosts(lp);
337 ComputeConstraintActivities(lp);
347 bool rhs_perturbation_is_too_large =
false;
348 bool cost_perturbation_is_too_large =
false;
349 bool primal_infeasibility_is_too_large =
false;
350 bool dual_infeasibility_is_too_large =
false;
351 bool primal_residual_is_too_large =
false;
352 bool dual_residual_is_too_large =
false;
355 ComputeMaxRhsPerturbationToEnforceOptimality(lp,
356 &rhs_perturbation_is_too_large);
357 ComputeMaxCostPerturbationToEnforceOptimality(
358 lp, &cost_perturbation_is_too_large);
359 const double primal_infeasibility =
360 ComputePrimalValueInfeasibility(lp, &primal_infeasibility_is_too_large);
361 const double dual_infeasibility =
362 ComputeDualValueInfeasibility(lp, &dual_infeasibility_is_too_large);
363 const double primal_residual =
364 ComputeActivityInfeasibility(lp, &primal_residual_is_too_large);
365 const double dual_residual =
366 ComputeReducedCostInfeasibility(lp, &dual_residual_is_too_large);
371 max_absolute_primal_infeasibility_ =
372 std::max(primal_infeasibility, primal_residual);
373 max_absolute_dual_infeasibility_ =
374 std::max(dual_infeasibility, dual_residual);
375 SOLVER_LOG(&logger_,
"Max. primal infeasibility = ",
376 max_absolute_primal_infeasibility_);
378 "Max. dual infeasibility = ", max_absolute_dual_infeasibility_);
383 const double objective_error_ub = ComputeMaxExpectedObjectiveError(lp);
384 SOLVER_LOG(&logger_,
"Objective error <= ", objective_error_ub);
390 if (primal_infeasibility != 0.0 || dual_infeasibility != 0.0) {
391 LOG(
ERROR) <<
"Primal/dual values have been moved to their bounds. " 392 <<
"Therefore the primal/dual infeasibilities should be " 393 <<
"exactly zero (but not the residuals). If this message " 394 <<
"appears, there is probably a bug in " 395 <<
"MovePrimalValuesWithinBounds() or in " 396 <<
"MoveDualValuesWithinBounds().";
398 if (rhs_perturbation_is_too_large) {
399 SOLVER_LOG(&logger_,
"The needed rhs perturbation is too large !!");
404 if (cost_perturbation_is_too_large) {
405 SOLVER_LOG(&logger_,
"The needed cost perturbation is too large !!");
416 if (std::abs(primal_objective_value - dual_objective_value) >
417 objective_error_ub) {
419 "The objective gap of the final solution is too large.");
427 (primal_residual_is_too_large || primal_infeasibility_is_too_large)) {
429 "The primal infeasibility of the final solution is too large.");
436 (dual_residual_is_too_large || dual_infeasibility_is_too_large)) {
438 "The dual infeasibility of the final solution is too large.");
444 may_have_multiple_solutions_ =
449 bool LPSolver::IsOptimalSolutionOnFacet(
const LinearProgram& lp) {
454 const double kReducedCostTolerance = 1e-9;
455 const double kBoundTolerance = 1e-7;
457 for (ColIndex
col(0);
col < num_cols; ++
col) {
463 kReducedCostTolerance) &&
470 for (RowIndex
row(0);
row < num_rows; ++
row) {
476 kReducedCostTolerance) &&
486 return problem_objective_value_;
490 return max_absolute_primal_infeasibility_;
494 return max_absolute_dual_infeasibility_;
498 return may_have_multiple_solutions_;
502 return num_revised_simplex_iterations_;
506 return revised_simplex_ ==
nullptr ? 0.0
507 : revised_simplex_->DeterministicTime();
510 void LPSolver::MovePrimalValuesWithinBounds(
const LinearProgram& lp) {
514 for (ColIndex
col(0);
col < num_cols; ++
col) {
524 SOLVER_LOG(&logger_,
"Max. primal values move = ", error);
527 void LPSolver::MoveDualValuesWithinBounds(
const LinearProgram& lp) {
528 const RowIndex num_rows = lp.num_constraints();
530 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
532 for (RowIndex
row(0);
row < num_rows; ++
row) {
537 Fractional minimization_dual_value = optimization_sign * dual_values_[
row];
539 error =
std::max(error, minimization_dual_value);
540 minimization_dual_value = 0.0;
543 error =
std::max(error, -minimization_dual_value);
544 minimization_dual_value = 0.0;
546 dual_values_[
row] = optimization_sign * minimization_dual_value;
548 SOLVER_LOG(&logger_,
"Max. dual values move = ", error);
551 void LPSolver::ResizeSolution(RowIndex num_rows, ColIndex num_cols) {
552 primal_values_.
resize(num_cols, 0.0);
553 reduced_costs_.
resize(num_cols, 0.0);
556 dual_values_.resize(num_rows, 0.0);
557 constraint_activities_.
resize(num_rows, 0.0);
561 void LPSolver::RunRevisedSimplexIfNeeded(ProblemSolution* solution,
572 if (revised_simplex_ ==
nullptr) {
573 revised_simplex_ = absl::make_unique<RevisedSimplex>();
574 revised_simplex_->SetLogger(&logger_);
576 revised_simplex_->SetParameters(parameters_);
577 if (revised_simplex_->Solve(current_linear_program_,
time_limit).ok()) {
578 num_revised_simplex_iterations_ = revised_simplex_->GetNumberOfIterations();
579 solution->status = revised_simplex_->GetProblemStatus();
582 const ColIndex num_cols = solution->primal_values.size();
583 DCHECK_LE(num_cols, revised_simplex_->GetProblemNumCols());
584 for (ColIndex
col(0);
col < num_cols; ++
col) {
585 solution->primal_values[
col] = revised_simplex_->GetVariableValue(
col);
586 solution->variable_statuses[
col] =
587 revised_simplex_->GetVariableStatus(
col);
589 const RowIndex num_rows = revised_simplex_->GetProblemNumRows();
590 DCHECK_EQ(solution->dual_values.size(), num_rows);
591 for (RowIndex
row(0);
row < num_rows; ++
row) {
592 solution->dual_values[
row] = revised_simplex_->GetDualValue(
row);
593 solution->constraint_statuses[
row] =
594 revised_simplex_->GetConstraintStatus(
row);
598 primal_ray_ = revised_simplex_->GetPrimalRay();
600 primal_ray_.
resize(num_cols);
602 constraints_dual_ray_ = revised_simplex_->GetDualRay();
603 variable_bounds_dual_ray_ =
604 revised_simplex_->GetDualRayRowCombination();
606 variable_bounds_dual_ray_.
resize(num_cols);
625 SOLVER_LOG(&logger_,
"Error during the revised simplex algorithm.");
635 VLOG(1) <<
"Variable " <<
col <<
" status is " 637 <<
" and its bounds are [" << lb <<
", " << ub <<
"].";
642 VLOG(1) <<
"Constraint " <<
row <<
" status is " 644 <<
", " << ub <<
"].";
649 bool LPSolver::IsProblemSolutionConsistent(
650 const LinearProgram& lp,
const ProblemSolution& solution)
const {
651 const RowIndex num_rows = lp.num_constraints();
652 const ColIndex num_cols = lp.num_variables();
653 if (solution.variable_statuses.size() != num_cols)
return false;
654 if (solution.constraint_statuses.size() != num_rows)
return false;
655 if (solution.primal_values.size() != num_cols)
return false;
656 if (solution.dual_values.size() != num_rows)
return false;
665 RowIndex num_basic_variables(0);
666 for (ColIndex
col(0);
col < num_cols; ++
col) {
671 switch (solution.variable_statuses[
col]) {
675 ++num_basic_variables;
688 LogVariableStatusError(
col,
value, status, lb, ub);
693 if (
value != lb || lb == ub) {
694 LogVariableStatusError(
col,
value, status, lb, ub);
702 LogVariableStatusError(
col,
value, status, lb, ub);
708 LogVariableStatusError(
col,
value, status, lb, ub);
714 for (RowIndex
row(0);
row < num_rows; ++
row) {
725 if (dual_value != 0.0) {
726 VLOG(1) <<
"Constraint " <<
row <<
" is BASIC, but its dual value is " 727 << dual_value <<
" instead of 0.";
730 ++num_basic_variables;
736 if (ub - lb > 1e-12) {
737 LogConstraintStatusError(
row, status, lb, ub);
743 LogConstraintStatusError(
row, status, lb, ub);
749 LogConstraintStatusError(
row, status, lb, ub);
754 if (dual_value != 0.0) {
755 VLOG(1) <<
"Constraint " <<
row <<
" is FREE, but its dual value is " 756 << dual_value <<
" instead of 0.";
760 LogConstraintStatusError(
row, status, lb, ub);
769 if (num_basic_variables != num_rows) {
770 VLOG(1) <<
"Wrong number of basic variables: " << num_basic_variables;
780 Fractional LPSolver::ComputeMaxCostPerturbationToEnforceOptimality(
781 const LinearProgram& lp,
bool* is_too_large) {
783 const ColIndex num_cols = lp.num_variables();
784 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
786 for (ColIndex
col(0);
col < num_cols; ++
col) {
790 const Fractional reduced_cost = optimization_sign * reduced_costs_[
col];
795 max_cost_correction =
796 std::max(max_cost_correction, std::abs(reduced_cost));
798 std::abs(reduced_cost) >
799 AllowedError(tolerance, lp.objective_coefficients()[
col]);
802 SOLVER_LOG(&logger_,
"Max. cost perturbation = ", max_cost_correction);
803 return max_cost_correction;
808 Fractional LPSolver::ComputeMaxRhsPerturbationToEnforceOptimality(
809 const LinearProgram& lp,
bool* is_too_large) {
811 const RowIndex num_rows = lp.num_constraints();
813 for (RowIndex
row(0);
row < num_rows; ++
row) {
823 allowed_error = AllowedError(tolerance,
lower_bound);
827 allowed_error = AllowedError(tolerance,
upper_bound);
829 max_rhs_correction =
std::max(max_rhs_correction, rhs_error);
830 *is_too_large |= rhs_error > allowed_error;
832 SOLVER_LOG(&logger_,
"Max. rhs perturbation = ", max_rhs_correction);
833 return max_rhs_correction;
836 void LPSolver::ComputeConstraintActivities(
const LinearProgram& lp) {
837 const RowIndex num_rows = lp.num_constraints();
838 const ColIndex num_cols = lp.num_variables();
840 constraint_activities_.
assign(num_rows, 0.0);
841 for (ColIndex
col(0);
col < num_cols; ++
col) {
842 lp.GetSparseColumn(
col).AddMultipleToDenseVector(primal_values_[
col],
843 &constraint_activities_);
847 void LPSolver::ComputeReducedCosts(
const LinearProgram& lp) {
848 const RowIndex num_rows = lp.num_constraints();
849 const ColIndex num_cols = lp.num_variables();
850 DCHECK_EQ(num_rows, dual_values_.size());
851 reduced_costs_.resize(num_cols, 0.0);
852 for (ColIndex
col(0);
col < num_cols; ++
col) {
853 reduced_costs_[
col] = lp.objective_coefficients()[
col] -
858 double LPSolver::ComputeObjective(
const LinearProgram& lp) {
859 const ColIndex num_cols = lp.num_variables();
862 for (ColIndex
col(0);
col < num_cols; ++
col) {
863 sum.
Add(lp.objective_coefficients()[
col] * primal_values_[
col]);
884 double LPSolver::ComputeDualObjective(
const LinearProgram& lp) {
888 const RowIndex num_rows = lp.num_constraints();
889 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
890 for (RowIndex
row(0);
row < num_rows; ++
row) {
895 const Fractional corrected_value = optimization_sign * dual_values_[
row];
920 const ColIndex num_cols = lp.num_variables();
921 for (ColIndex
col(0);
col < num_cols; ++
col) {
927 const Fractional reduced_cost = optimization_sign * reduced_costs_[
col];
933 reduced_cost > 0.0) {
936 reduced_cost < 0.0) {
942 dual_objective.Add(optimization_sign * correction);
944 return dual_objective.Value();
947 double LPSolver::ComputeMaxExpectedObjectiveError(
const LinearProgram& lp) {
948 const ColIndex num_cols = lp.num_variables();
952 for (ColIndex
col(0);
col < num_cols; ++
col) {
956 primal_objective_error += std::abs(lp.objective_coefficients()[
col]) *
957 AllowedError(tolerance, primal_values_[
col]);
959 return primal_objective_error;
962 double LPSolver::ComputePrimalValueInfeasibility(
const LinearProgram& lp,
963 bool* is_too_large) {
964 double infeasibility = 0.0;
966 const ColIndex num_cols = lp.num_variables();
967 for (ColIndex
col(0);
col < num_cols; ++
col) {
974 infeasibility =
std::max(infeasibility, error);
975 *is_too_large |= error > AllowedError(tolerance,
upper_bound);
980 infeasibility =
std::max(infeasibility, error);
981 *is_too_large |= error > AllowedError(tolerance,
upper_bound);
985 infeasibility =
std::max(infeasibility, error);
986 *is_too_large |= error > AllowedError(tolerance,
lower_bound);
989 return infeasibility;
992 double LPSolver::ComputeActivityInfeasibility(
const LinearProgram& lp,
993 bool* is_too_large) {
994 double infeasibility = 0.0;
995 int num_problematic_rows(0);
996 const RowIndex num_rows = lp.num_constraints();
998 for (RowIndex
row(0);
row < num_rows; ++
row) {
1007 VLOG(2) <<
"Row " <<
row.value() <<
" has activity " << activity
1008 <<
" which is different from " <<
upper_bound <<
" by " 1010 ++num_problematic_rows;
1017 if (row_excess > AllowedError(tolerance,
upper_bound)) {
1018 VLOG(2) <<
"Row " <<
row.value() <<
" has activity " << activity
1019 <<
", exceeding its upper bound " <<
upper_bound <<
" by " 1021 ++num_problematic_rows;
1023 infeasibility =
std::max(infeasibility, row_excess);
1027 if (row_deficit > AllowedError(tolerance,
lower_bound)) {
1028 VLOG(2) <<
"Row " <<
row.value() <<
" has activity " << activity
1029 <<
", below its lower bound " <<
lower_bound <<
" by " 1031 ++num_problematic_rows;
1033 infeasibility =
std::max(infeasibility, row_deficit);
1036 if (num_problematic_rows > 0) {
1037 *is_too_large =
true;
1038 VLOG(1) <<
"Number of infeasible rows = " << num_problematic_rows;
1040 return infeasibility;
1043 double LPSolver::ComputeDualValueInfeasibility(
const LinearProgram& lp,
1044 bool* is_too_large) {
1046 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
1047 double infeasibility = 0.0;
1048 const RowIndex num_rows = lp.num_constraints();
1049 for (RowIndex
row(0);
row < num_rows; ++
row) {
1054 const Fractional minimization_dual_value = optimization_sign * dual_value;
1056 *is_too_large |= minimization_dual_value > allowed_error;
1057 infeasibility =
std::max(infeasibility, minimization_dual_value);
1060 *is_too_large |= -minimization_dual_value > allowed_error;
1061 infeasibility =
std::max(infeasibility, -minimization_dual_value);
1064 return infeasibility;
1067 double LPSolver::ComputeReducedCostInfeasibility(
const LinearProgram& lp,
1068 bool* is_too_large) {
1069 const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
1070 double infeasibility = 0.0;
1071 const ColIndex num_cols = lp.num_variables();
1073 for (ColIndex
col(0);
col < num_cols; ++
col) {
1079 optimization_sign * reduced_cost;
1081 AllowedError(tolerance, lp.objective_coefficients()[
col]);
1083 *is_too_large |= minimization_reduced_cost > allowed_error;
1084 infeasibility =
std::max(infeasibility, minimization_reduced_cost);
1087 *is_too_large |= -minimization_reduced_cost > allowed_error;
1088 infeasibility =
std::max(infeasibility, -minimization_reduced_cost);
1091 return infeasibility;
void EnableLogging(bool enable)
void MergeFrom(const GlopParameters &from)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
std::string GetObjectiveStatsString() const
void LinearProgramToMPModelProto(const LinearProgram &input, MPModelProto *output)
void Add(const FpNumber &value)
Fractional GetMaximumPrimalInfeasibility() const
const GlopParameters & GetParameters() const
#define SOLVER_LOG(logger,...)
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
RowIndex num_constraints() const
ModelSharedTimeLimit * time_limit
#define VLOG(verboselevel)
bool IsMaximizationProblem() const
Fractional GetObjectiveValue() const
void SetLogToStdOut(bool enable)
std::string GetProblemStatusString(ProblemStatus problem_status)
double solution_feasibility_tolerance() const
bool provide_strong_optimal_guarantee() const
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
bool Run(LinearProgram *lp) final
void assign(IntType size, const T &v)
bool IsFinite(Fractional value)
bool log_search_progress() const
Fractional objective_offset() const
void SetParameters(const GlopParameters ¶meters)
const DenseColumn & constraint_upper_bounds() const
VariableStatusRow variable_statuses
ProblemStatus LoadAndVerifySolution(const LinearProgram &lp, const ProblemSolution &solution)
ProblemStatus status() const
bool use_preprocessing() const
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...
Fractional objective_scaling_factor() const
void ChangeSign(StrictITIVector< IndexType, Fractional > *data)
std::string GetDimensionString() const
const DenseColumn & constraint_lower_bounds() const
void SetLogger(SolverLogger *logger)
void SetTimeLimit(TimeLimit *time_limit)
std::string GetConstraintStatusString(ConstraintStatus status)
GlopParameters * GetMutableParameters()
VariableStatusRow statuses
bool change_status_to_imprecise() const
AccurateSum< Fractional > KahanSum
int GetNumberOfSimplexIterations() const
void DestructiveRecoverSolution(ProblemSolution *solution)
bool AreWithinAbsoluteTolerance(FloatType x, FloatType y, FloatType absolute_tolerance)
void push_back(const value_type &x)
bool WriteProtoToFile(absl::string_view filename, const google::protobuf::Message &proto, ProtoWriteFormat proto_write_format, bool gzipped, bool append_extension_to_file_name)
double DeterministicTime() const
bool MayHaveMultipleOptimalSolutions() const
ColIndex num_variables() const
ConstraintStatusColumn constraint_statuses
void resize(IntType size)
#define DCHECK(condition)
const DenseRow & variable_upper_bounds() const
const DenseRow & variable_lower_bounds() const
bool LoggingIsEnabled() const
#define DCHECK_EQ(val1, val2)
const VariableStatusRow & variable_statuses() const
std::string GetVariableStatusString(VariableStatus status)
bool log_to_stdout() const
#define DCHECK_LE(val1, val2)
const ConstraintStatusColumn & constraint_statuses() const
Collection of objects used to extend the Constraint Solver library.
SolverLogger & GetSolverLogger()
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
void ClearTransposeMatrix()
std::string GetBoundsStatsString() const
#define VLOG_IS_ON(verboselevel)
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
void PopulateFromLinearProgram(const LinearProgram &linear_program)
ABSL_FLAG(bool, lp_dump_to_proto_file, false, "Tells whether do dump the problem to a protobuf file.")
Fractional GetMaximumDualInfeasibility() const