OR-Tools  8.0
lp_solver.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "ortools/glop/lp_solver.h"
15 
16 #include <cmath>
17 #include <stack>
18 #include <vector>
19 
20 #include "absl/memory/memory.h"
21 #include "absl/strings/match.h"
22 #include "absl/strings/str_format.h"
25 #include "ortools/base/timer.h"
27 #include "ortools/glop/status.h"
31 #include "ortools/util/fp_utils.h"
32 
33 // TODO(user): abstract this in some way to the port directory.
34 #ifndef __PORTABLE_PLATFORM__
35 #include "ortools/util/file_util.h"
36 #endif
37 
38 DEFINE_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.");
42 DEFINE_bool(lp_dump_to_proto_file, false,
43  "Tells whether do dump the problem to a protobuf file.");
44 DEFINE_bool(lp_dump_compressed_file, true,
45  "Whether the proto dump file is compressed.");
46 DEFINE_bool(lp_dump_binary_file, false,
47  "Whether the proto dump file is binary.");
48 DEFINE_int32(lp_dump_file_number, -1,
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().");
52 DEFINE_string(lp_dump_dir, "/tmp", "Directory where dump files are written.");
53 DEFINE_string(lp_dump_file_basename, "",
54  "Base name for dump files. LinearProgram::name_ is used if "
55  "lp_dump_file_basename is empty. If LinearProgram::name_ is "
56  "empty, \"linear_program_dump_file\" is used.");
57 
58 namespace operations_research {
59 namespace glop {
60 namespace {
61 
62 // Writes a LinearProgram to a file if FLAGS_lp_dump_to_proto_file is true.
63 // The integer num is appended to the base name of the file.
64 // When this function is called from LPSolver::Solve(), num is usually the
65 // number of times Solve() was called.
66 // For a LinearProgram whose name is "LinPro", and num = 48, the default output
67 // file will be /tmp/LinPro-000048.pb.gz.
68 //
69 // Warning: is a no-op on portable platforms (android, ios, etc).
70 void DumpLinearProgramIfRequiredByFlags(const LinearProgram& linear_program,
71  int num) {
72  if (!FLAGS_lp_dump_to_proto_file) return;
73 #ifdef __PORTABLE_PLATFORM__
74  LOG(WARNING) << "DumpLinearProgramIfRequiredByFlags(linear_program, num) "
75  "requested for linear_program.name()='"
76  << linear_program.name() << "', num=" << num
77  << " but is not implemented for this platform.";
78 #else
79  std::string filename = FLAGS_lp_dump_file_basename;
80  if (filename.empty()) {
81  if (linear_program.name().empty()) {
82  filename = "linear_program_dump";
83  } else {
84  filename = linear_program.name();
85  }
86  }
87  const int file_num =
88  FLAGS_lp_dump_file_number >= 0 ? FLAGS_lp_dump_file_number : num;
89  absl::StrAppendFormat(&filename, "-%06d.pb", file_num);
90  const std::string filespec = absl::StrCat(FLAGS_lp_dump_dir, "/", filename);
91  MPModelProto proto;
92  LinearProgramToMPModelProto(linear_program, &proto);
93  const ProtoWriteFormat write_format = FLAGS_lp_dump_binary_file
96  if (!WriteProtoToFile(filespec, proto, write_format,
97  FLAGS_lp_dump_compressed_file)) {
98  LOG(DFATAL) << "Could not write " << filespec;
99  }
100 #endif
101 }
102 
103 } // anonymous namespace
104 
105 // --------------------------------------------------------
106 // LPSolver
107 // --------------------------------------------------------
108 
109 LPSolver::LPSolver() : num_solves_(0) {}
110 
111 void LPSolver::SetParameters(const GlopParameters& parameters) {
112  parameters_ = parameters;
113 }
114 
115 const GlopParameters& LPSolver::GetParameters() const { return parameters_; }
116 
117 GlopParameters* LPSolver::GetMutableParameters() { return &parameters_; }
118 
120  std::unique_ptr<TimeLimit> time_limit =
121  TimeLimit::FromParameters(parameters_);
122  return SolveWithTimeLimit(lp, time_limit.get());
123 }
124 
127  if (time_limit == nullptr) {
128  LOG(DFATAL) << "SolveWithTimeLimit() called with a nullptr time_limit.";
130  }
131  ++num_solves_;
132  num_revised_simplex_iterations_ = 0;
133  DumpLinearProgramIfRequiredByFlags(lp, num_solves_);
134  // Check some preconditions.
135  if (!lp.IsCleanedUp()) {
136  LOG(DFATAL) << "The columns of the given linear program should be ordered "
137  << "by row and contain no zero coefficients. Call CleanUp() "
138  << "on it before calling Solve().";
139  ResizeSolution(lp.num_constraints(), lp.num_variables());
141  }
142  if (!lp.IsValid()) {
143  LOG(DFATAL) << "The given linear program is invalid. It contains NaNs, "
144  << "infinite coefficients or invalid bounds specification. "
145  << "You can construct it in debug mode to get the exact cause.";
146  ResizeSolution(lp.num_constraints(), lp.num_variables());
148  }
149  // Display a warning if running in non-opt, unless we're inside a unit test.
150  DLOG(WARNING)
151  << "\n******************************************************************"
152  "\n* WARNING: Glop will be very slow because it will use DCHECKs *"
153  "\n* to verify the results and the precision of the solver. *"
154  "\n* You can gain at least an order of magnitude speedup by *"
155  "\n* compiling with optimizations enabled and by defining NDEBUG. *"
156  "\n******************************************************************";
157 
158  // Note that we only activate the floating-point exceptions after we are sure
159  // that the program is valid. This way, if we have input NaNs, we will not
160  // crash.
161  ScopedFloatingPointEnv scoped_fenv;
162  if (FLAGS_lp_solver_enable_fp_exceptions) {
163 #ifdef _MSC_VER
164  scoped_fenv.EnableExceptions(_EM_INVALID | EM_ZERODIVIDE);
165 #else
166  scoped_fenv.EnableExceptions(FE_DIVBYZERO | FE_INVALID);
167 #endif
168  }
169 
170  // Make an internal copy of the problem for the preprocessing.
171  VLOG(1) << "Initial problem: " << lp.GetDimensionString();
172  VLOG(1) << "Objective stats: " << lp.GetObjectiveStatsString();
173  current_linear_program_.PopulateFromLinearProgram(lp);
174 
175  // Preprocess.
176  MainLpPreprocessor preprocessor(&parameters_);
177  preprocessor.SetTimeLimit(time_limit);
178 
179  const bool postsolve_is_needed = preprocessor.Run(&current_linear_program_);
180 
181  VLOG(1) << "Presolved problem: "
182  << current_linear_program_.GetDimensionString();
183 
184  // At this point, we need to initialize a ProblemSolution with the correct
185  // size and status.
186  ProblemSolution solution(current_linear_program_.num_constraints(),
187  current_linear_program_.num_variables());
188  solution.status = preprocessor.status();
189 
190  // Do not launch the solver if the time limit was already reached. This might
191  // mean that the pre-processors were not all run, and current_linear_program_
192  // might not be in a completely safe state.
193  if (!time_limit->LimitReached()) {
194  RunRevisedSimplexIfNeeded(&solution, time_limit);
195  }
196 
197  if (postsolve_is_needed) preprocessor.RecoverSolution(&solution);
198  const ProblemStatus status = LoadAndVerifySolution(lp, solution);
199 
200  // LOG some statistics that can be parsed by our benchmark script.
201  VLOG(1) << "status: " << status;
202  VLOG(1) << "objective: " << GetObjectiveValue();
203  VLOG(1) << "iterations: " << GetNumberOfSimplexIterations();
204  VLOG(1) << "time: " << time_limit->GetElapsedTime();
205  VLOG(1) << "deterministic_time: "
206  << time_limit->GetElapsedDeterministicTime();
207 
208  return status;
209 }
210 
212  ResizeSolution(RowIndex(0), ColIndex(0));
213  revised_simplex_.reset(nullptr);
214 }
215 
217  const VariableStatusRow& variable_statuses,
218  const ConstraintStatusColumn& constraint_statuses) {
219  // Create the associated basis state.
220  BasisState state;
221  state.statuses = variable_statuses;
222  for (const ConstraintStatus status : constraint_statuses) {
223  // Note the change of upper/lower bound between the status of a constraint
224  // and the status of its associated slack variable.
225  switch (status) {
228  break;
231  break;
234  break;
237  break;
240  break;
241  }
242  }
243  if (revised_simplex_ == nullptr) {
244  revised_simplex_ = absl::make_unique<RevisedSimplex>();
245  }
246  revised_simplex_->LoadStateForNextSolve(state);
247  if (parameters_.use_preprocessing()) {
248  LOG(WARNING) << "In GLOP, SetInitialBasis() was called but the parameter "
249  "use_preprocessing is true, this will likely not result in "
250  "what you want.";
251  }
252 }
253 
254 namespace {
255 // Computes the "real" problem objective from the one without offset nor
256 // scaling.
257 Fractional ProblemObjectiveValue(const LinearProgram& lp, Fractional value) {
258  return lp.objective_scaling_factor() * (value + lp.objective_offset());
259 }
260 
261 // Returns the allowed error magnitude for something that should evaluate to
262 // value under the given tolerance.
263 Fractional AllowedError(Fractional tolerance, Fractional value) {
264  return tolerance * std::max(1.0, std::abs(value));
265 }
266 } // namespace
267 
268 // TODO(user): Try to also check the precision of an INFEASIBLE or UNBOUNDED
269 // return status.
271  const ProblemSolution& solution) {
272  if (!IsProblemSolutionConsistent(lp, solution)) {
273  VLOG(1) << "Inconsistency detected in the solution.";
274  ResizeSolution(lp.num_constraints(), lp.num_variables());
276  }
277 
278  // Load the solution.
279  primal_values_ = solution.primal_values;
280  dual_values_ = solution.dual_values;
281  variable_statuses_ = solution.variable_statuses;
282  constraint_statuses_ = solution.constraint_statuses;
283  ProblemStatus status = solution.status;
284 
285  // Objective before eventually moving the primal/dual values inside their
286  // bounds.
287  ComputeReducedCosts(lp);
288  const Fractional primal_objective_value = ComputeObjective(lp);
289  const Fractional dual_objective_value = ComputeDualObjective(lp);
290  VLOG(1) << "Primal objective (before moving primal/dual values) = "
291  << absl::StrFormat("%.15E",
292  ProblemObjectiveValue(lp, primal_objective_value));
293  VLOG(1) << "Dual objective (before moving primal/dual values) = "
294  << absl::StrFormat("%.15E",
295  ProblemObjectiveValue(lp, dual_objective_value));
296 
297  // Eventually move the primal/dual values inside their bounds.
298  if (status == ProblemStatus::OPTIMAL &&
299  parameters_.provide_strong_optimal_guarantee()) {
300  MovePrimalValuesWithinBounds(lp);
301  MoveDualValuesWithinBounds(lp);
302  }
303 
304  // The reported objective to the user.
305  problem_objective_value_ = ProblemObjectiveValue(lp, ComputeObjective(lp));
306  VLOG(1) << "Primal objective (after moving primal/dual values) = "
307  << absl::StrFormat("%.15E", problem_objective_value_);
308 
309  ComputeReducedCosts(lp);
310  ComputeConstraintActivities(lp);
311 
312  // These will be set to true if the associated "infeasibility" is too large.
313  //
314  // The tolerance used is the parameter solution_feasibility_tolerance. To be
315  // somewhat independent of the original problem scaling, the thresholds used
316  // depend of the quantity involved and of its coordinates:
317  // - tolerance * max(1.0, abs(cost[col])) when a reduced cost is infeasible.
318  // - tolerance * max(1.0, abs(bound)) when a bound is crossed.
319  // - tolerance for an infeasible dual value (because the limit is always 0.0).
320  bool rhs_perturbation_is_too_large = false;
321  bool cost_perturbation_is_too_large = false;
322  bool primal_infeasibility_is_too_large = false;
323  bool dual_infeasibility_is_too_large = false;
324  bool primal_residual_is_too_large = false;
325  bool dual_residual_is_too_large = false;
326 
327  // Computes all the infeasiblities and update the Booleans above.
328  ComputeMaxRhsPerturbationToEnforceOptimality(lp,
329  &rhs_perturbation_is_too_large);
330  ComputeMaxCostPerturbationToEnforceOptimality(
331  lp, &cost_perturbation_is_too_large);
332  const double primal_infeasibility =
333  ComputePrimalValueInfeasibility(lp, &primal_infeasibility_is_too_large);
334  const double dual_infeasibility =
335  ComputeDualValueInfeasibility(lp, &dual_infeasibility_is_too_large);
336  const double primal_residual =
337  ComputeActivityInfeasibility(lp, &primal_residual_is_too_large);
338  const double dual_residual =
339  ComputeReducedCostInfeasibility(lp, &dual_residual_is_too_large);
340 
341  // TODO(user): the name is not really consistent since in practice those are
342  // the "residual" since the primal/dual infeasibility are zero when
343  // parameters_.provide_strong_optimal_guarantee() is true.
344  max_absolute_primal_infeasibility_ =
345  std::max(primal_infeasibility, primal_residual);
346  max_absolute_dual_infeasibility_ =
347  std::max(dual_infeasibility, dual_residual);
348  VLOG(1) << "Max. primal infeasibility = "
349  << max_absolute_primal_infeasibility_;
350  VLOG(1) << "Max. dual infeasibility = " << max_absolute_dual_infeasibility_;
351 
352  // Now that all the relevant quantities are computed, we check the precision
353  // and optimality of the result. See Chvatal pp. 61-62. If any of the tests
354  // fail, we return the IMPRECISE status.
355  const double objective_error_ub = ComputeMaxExpectedObjectiveError(lp);
356  VLOG(1) << "Objective error <= " << objective_error_ub;
357 
358  if (status == ProblemStatus::OPTIMAL &&
359  parameters_.provide_strong_optimal_guarantee()) {
360  // If the primal/dual values were moved to the bounds, then the primal/dual
361  // infeasibilities should be exactly zero (but not the residuals).
362  if (primal_infeasibility != 0.0 || dual_infeasibility != 0.0) {
363  LOG(ERROR) << "Primal/dual values have been moved to their bounds. "
364  << "Therefore the primal/dual infeasibilities should be "
365  << "exactly zero (but not the residuals). If this message "
366  << "appears, there is probably a bug in "
367  << "MovePrimalValuesWithinBounds() or in "
368  << "MoveDualValuesWithinBounds().";
369  }
370  if (rhs_perturbation_is_too_large) {
371  VLOG(1) << "The needed rhs perturbation is too large !!";
372  status = ProblemStatus::IMPRECISE;
373  }
374  if (cost_perturbation_is_too_large) {
375  VLOG(1) << "The needed cost perturbation is too large !!";
376  status = ProblemStatus::IMPRECISE;
377  }
378  }
379 
380  // Note that we compare the values without offset nor scaling. We also need to
381  // compare them before we move the primal/dual values, otherwise we lose some
382  // precision since the values are modified independently of each other.
383  if (status == ProblemStatus::OPTIMAL) {
384  if (std::abs(primal_objective_value - dual_objective_value) >
385  objective_error_ub) {
386  VLOG(1) << "The objective gap of the final solution is too large.";
387  status = ProblemStatus::IMPRECISE;
388  }
389  }
390  if ((status == ProblemStatus::OPTIMAL ||
391  status == ProblemStatus::PRIMAL_FEASIBLE) &&
392  (primal_residual_is_too_large || primal_infeasibility_is_too_large)) {
393  VLOG(1) << "The primal infeasibility of the final solution is too large.";
394  status = ProblemStatus::IMPRECISE;
395  }
396  if ((status == ProblemStatus::OPTIMAL ||
397  status == ProblemStatus::DUAL_FEASIBLE) &&
398  (dual_residual_is_too_large || dual_infeasibility_is_too_large)) {
399  VLOG(1) << "The dual infeasibility of the final solution is too large.";
400  status = ProblemStatus::IMPRECISE;
401  }
402 
403  may_have_multiple_solutions_ =
404  (status == ProblemStatus::OPTIMAL) ? IsOptimalSolutionOnFacet(lp) : false;
405  return status;
406 }
407 
408 bool LPSolver::IsOptimalSolutionOnFacet(const LinearProgram& lp) {
409  // Note(user): We use the following same two tolerances for the dual and
410  // primal values.
411  // TODO(user): investigate whether to use the tolerances defined in
412  // parameters.proto.
413  const double kReducedCostTolerance = 1e-9;
414  const double kBoundTolerance = 1e-7;
415  const ColIndex num_cols = lp.num_variables();
416  for (ColIndex col(0); col < num_cols; ++col) {
417  if (variable_statuses_[col] == VariableStatus::FIXED_VALUE) continue;
418  const Fractional lower_bound = lp.variable_lower_bounds()[col];
419  const Fractional upper_bound = lp.variable_upper_bounds()[col];
420  const Fractional value = primal_values_[col];
421  if (AreWithinAbsoluteTolerance(reduced_costs_[col], 0.0,
422  kReducedCostTolerance) &&
423  (AreWithinAbsoluteTolerance(value, lower_bound, kBoundTolerance) ||
424  AreWithinAbsoluteTolerance(value, upper_bound, kBoundTolerance))) {
425  return true;
426  }
427  }
428  const RowIndex num_rows = lp.num_constraints();
429  for (RowIndex row(0); row < num_rows; ++row) {
430  if (constraint_statuses_[row] == ConstraintStatus::FIXED_VALUE) continue;
431  const Fractional lower_bound = lp.constraint_lower_bounds()[row];
432  const Fractional upper_bound = lp.constraint_upper_bounds()[row];
433  const Fractional activity = constraint_activities_[row];
434  if (AreWithinAbsoluteTolerance(dual_values_[row], 0.0,
435  kReducedCostTolerance) &&
436  (AreWithinAbsoluteTolerance(activity, lower_bound, kBoundTolerance) ||
437  AreWithinAbsoluteTolerance(activity, upper_bound, kBoundTolerance))) {
438  return true;
439  }
440  }
441  return false;
442 }
443 
445  return problem_objective_value_;
446 }
447 
449  return max_absolute_primal_infeasibility_;
450 }
451 
453  return max_absolute_dual_infeasibility_;
454 }
455 
457  return may_have_multiple_solutions_;
458 }
459 
461  return num_revised_simplex_iterations_;
462 }
463 
465  return revised_simplex_ == nullptr ? 0.0
466  : revised_simplex_->DeterministicTime();
467 }
468 
469 void LPSolver::MovePrimalValuesWithinBounds(const LinearProgram& lp) {
470  const ColIndex num_cols = lp.num_variables();
471  DCHECK_EQ(num_cols, primal_values_.size());
472  Fractional error = 0.0;
473  for (ColIndex col(0); col < num_cols; ++col) {
474  const Fractional lower_bound = lp.variable_lower_bounds()[col];
475  const Fractional upper_bound = lp.variable_upper_bounds()[col];
476  DCHECK_LE(lower_bound, upper_bound);
477 
478  error = std::max(error, primal_values_[col] - upper_bound);
479  error = std::max(error, lower_bound - primal_values_[col]);
480  primal_values_[col] = std::min(primal_values_[col], upper_bound);
481  primal_values_[col] = std::max(primal_values_[col], lower_bound);
482  }
483  VLOG(1) << "Max. primal values move = " << error;
484 }
485 
486 void LPSolver::MoveDualValuesWithinBounds(const LinearProgram& lp) {
487  const RowIndex num_rows = lp.num_constraints();
488  DCHECK_EQ(num_rows, dual_values_.size());
489  const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
490  Fractional error = 0.0;
491  for (RowIndex row(0); row < num_rows; ++row) {
492  const Fractional lower_bound = lp.constraint_lower_bounds()[row];
493  const Fractional upper_bound = lp.constraint_upper_bounds()[row];
494 
495  // For a minimization problem, we want a lower bound.
496  Fractional minimization_dual_value = optimization_sign * dual_values_[row];
497  if (lower_bound == -kInfinity && minimization_dual_value > 0.0) {
498  error = std::max(error, minimization_dual_value);
499  minimization_dual_value = 0.0;
500  }
501  if (upper_bound == kInfinity && minimization_dual_value < 0.0) {
502  error = std::max(error, -minimization_dual_value);
503  minimization_dual_value = 0.0;
504  }
505  dual_values_[row] = optimization_sign * minimization_dual_value;
506  }
507  VLOG(1) << "Max. dual values move = " << error;
508 }
509 
510 void LPSolver::ResizeSolution(RowIndex num_rows, ColIndex num_cols) {
511  primal_values_.resize(num_cols, 0.0);
512  reduced_costs_.resize(num_cols, 0.0);
513  variable_statuses_.resize(num_cols, VariableStatus::FREE);
514 
515  dual_values_.resize(num_rows, 0.0);
516  constraint_activities_.resize(num_rows, 0.0);
517  constraint_statuses_.resize(num_rows, ConstraintStatus::FREE);
518 }
519 
520 void LPSolver::RunRevisedSimplexIfNeeded(ProblemSolution* solution,
521  TimeLimit* time_limit) {
522  // Note that the transpose matrix is no longer needed at this point.
523  // This helps reduce the peak memory usage of the solver.
524  current_linear_program_.ClearTransposeMatrix();
525  if (solution->status != ProblemStatus::INIT) return;
526  if (revised_simplex_ == nullptr) {
527  revised_simplex_ = absl::make_unique<RevisedSimplex>();
528  }
529  revised_simplex_->SetParameters(parameters_);
530  if (revised_simplex_->Solve(current_linear_program_, time_limit).ok()) {
531  num_revised_simplex_iterations_ = revised_simplex_->GetNumberOfIterations();
532  solution->status = revised_simplex_->GetProblemStatus();
533 
534  const ColIndex num_cols = revised_simplex_->GetProblemNumCols();
535  DCHECK_EQ(solution->primal_values.size(), num_cols);
536  for (ColIndex col(0); col < num_cols; ++col) {
537  solution->primal_values[col] = revised_simplex_->GetVariableValue(col);
538  solution->variable_statuses[col] =
539  revised_simplex_->GetVariableStatus(col);
540  }
541 
542  const RowIndex num_rows = revised_simplex_->GetProblemNumRows();
543  DCHECK_EQ(solution->dual_values.size(), num_rows);
544  for (RowIndex row(0); row < num_rows; ++row) {
545  solution->dual_values[row] = revised_simplex_->GetDualValue(row);
546  solution->constraint_statuses[row] =
547  revised_simplex_->GetConstraintStatus(row);
548  }
549  } else {
550  VLOG(1) << "Error during the revised simplex algorithm.";
551  solution->status = ProblemStatus::ABNORMAL;
552  }
553 }
554 
555 namespace {
556 
557 void LogVariableStatusError(ColIndex col, Fractional value,
558  VariableStatus status, Fractional lb,
559  Fractional ub) {
560  VLOG(1) << "Variable " << col << " status is "
561  << GetVariableStatusString(status) << " but its value is " << value
562  << " and its bounds are [" << lb << ", " << ub << "].";
563 }
564 
565 void LogConstraintStatusError(RowIndex row, ConstraintStatus status,
566  Fractional lb, Fractional ub) {
567  VLOG(1) << "Constraint " << row << " status is "
568  << GetConstraintStatusString(status) << " but its bounds are [" << lb
569  << ", " << ub << "].";
570 }
571 
572 } // namespace
573 
574 bool LPSolver::IsProblemSolutionConsistent(
575  const LinearProgram& lp, const ProblemSolution& solution) const {
576  const RowIndex num_rows = lp.num_constraints();
577  const ColIndex num_cols = lp.num_variables();
578  if (solution.variable_statuses.size() != num_cols) return false;
579  if (solution.constraint_statuses.size() != num_rows) return false;
580  if (solution.primal_values.size() != num_cols) return false;
581  if (solution.dual_values.size() != num_rows) return false;
582  if (solution.status != ProblemStatus::OPTIMAL &&
583  solution.status != ProblemStatus::PRIMAL_FEASIBLE &&
584  solution.status != ProblemStatus::DUAL_FEASIBLE) {
585  return true;
586  }
587 
588  // This checks that the variable statuses verify the properties described
589  // in the VariableStatus declaration.
590  RowIndex num_basic_variables(0);
591  for (ColIndex col(0); col < num_cols; ++col) {
592  const Fractional value = solution.primal_values[col];
593  const Fractional lb = lp.variable_lower_bounds()[col];
594  const Fractional ub = lp.variable_upper_bounds()[col];
595  const VariableStatus status = solution.variable_statuses[col];
596  switch (solution.variable_statuses[col]) {
598  // TODO(user): Check that the reduced cost of this column is epsilon
599  // close to zero.
600  ++num_basic_variables;
601  break;
603  // TODO(user): Because of scaling, it is possible that a FIXED_VALUE
604  // status (only reserved for the exact lb == ub case) is now set for a
605  // variable where (ub == lb + epsilon). So we do not check here that the
606  // two bounds are exactly equal. The best is probably to remove the
607  // FIXED status from the API completely and report one of AT_LOWER_BOUND
608  // or AT_UPPER_BOUND instead. This also allows to indicate if at
609  // optimality, the objective is limited because of this variable lower
610  // bound or its upper bound. Note that there are other TODOs in the
611  // codebase about removing this FIXED_VALUE status.
612  if (value != ub && value != lb) {
613  LogVariableStatusError(col, value, status, lb, ub);
614  return false;
615  }
616  break;
618  if (value != lb || lb == ub) {
619  LogVariableStatusError(col, value, status, lb, ub);
620  return false;
621  }
622  break;
624  // TODO(user): revert to an exact comparison once the bug causing this
625  // to fail has been fixed.
626  if (!AreWithinAbsoluteTolerance(value, ub, 1e-7) || lb == ub) {
627  LogVariableStatusError(col, value, status, lb, ub);
628  return false;
629  }
630  break;
632  if (lb != -kInfinity || ub != kInfinity || value != 0.0) {
633  LogVariableStatusError(col, value, status, lb, ub);
634  return false;
635  }
636  break;
637  }
638  }
639  for (RowIndex row(0); row < num_rows; ++row) {
640  const Fractional dual_value = solution.dual_values[row];
641  const Fractional lb = lp.constraint_lower_bounds()[row];
642  const Fractional ub = lp.constraint_upper_bounds()[row];
643  const ConstraintStatus status = solution.constraint_statuses[row];
644 
645  // The activity value is not checked since it is imprecise.
646  // TODO(user): Check that the activity is epsilon close to the expected
647  // value.
648  switch (status) {
650  if (dual_value != 0.0) {
651  VLOG(1) << "Constraint " << row << " is BASIC, but its dual value is "
652  << dual_value << " instead of 0.";
653  return false;
654  }
655  ++num_basic_variables;
656  break;
658  // Exactly the same remark as for the VariableStatus::FIXED_VALUE case
659  // above. Because of precision error, this can happen when the
660  // difference between the two bounds is small and not just exactly zero.
661  if (ub - lb > 1e-12) {
662  LogConstraintStatusError(row, status, lb, ub);
663  return false;
664  }
665  break;
667  if (lb == -kInfinity) {
668  LogConstraintStatusError(row, status, lb, ub);
669  return false;
670  }
671  break;
673  if (ub == kInfinity) {
674  LogConstraintStatusError(row, status, lb, ub);
675  return false;
676  }
677  break;
679  if (dual_value != 0.0) {
680  VLOG(1) << "Constraint " << row << " is FREE, but its dual value is "
681  << dual_value << " instead of 0.";
682  return false;
683  }
684  if (lb != -kInfinity || ub != kInfinity) {
685  LogConstraintStatusError(row, status, lb, ub);
686  return false;
687  }
688  break;
689  }
690  }
691 
692  // TODO(user): We could check in debug mode (because it will be costly) that
693  // the basis is actually factorizable.
694  if (num_basic_variables != num_rows) {
695  VLOG(1) << "Wrong number of basic variables: " << num_basic_variables;
696  return false;
697  }
698  return true;
699 }
700 
701 // This computes by how much the objective must be perturbed to enforce the
702 // following complementary slackness conditions:
703 // - Reduced cost is exactly zero for FREE and BASIC variables.
704 // - Reduced cost is of the correct sign for variables at their bounds.
705 Fractional LPSolver::ComputeMaxCostPerturbationToEnforceOptimality(
706  const LinearProgram& lp, bool* is_too_large) {
707  Fractional max_cost_correction = 0.0;
708  const ColIndex num_cols = lp.num_variables();
709  const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
710  const Fractional tolerance = parameters_.solution_feasibility_tolerance();
711  for (ColIndex col(0); col < num_cols; ++col) {
712  // We correct the reduced cost, so we have a minimization problem and
713  // thus the dual objective value will be a lower bound of the primal
714  // objective.
715  const Fractional reduced_cost = optimization_sign * reduced_costs_[col];
716  const VariableStatus status = variable_statuses_[col];
717  if (status == VariableStatus::BASIC || status == VariableStatus::FREE ||
718  (status == VariableStatus::AT_UPPER_BOUND && reduced_cost > 0.0) ||
719  (status == VariableStatus::AT_LOWER_BOUND && reduced_cost < 0.0)) {
720  max_cost_correction =
721  std::max(max_cost_correction, std::abs(reduced_cost));
722  *is_too_large |=
723  std::abs(reduced_cost) >
724  AllowedError(tolerance, lp.objective_coefficients()[col]);
725  }
726  }
727  VLOG(1) << "Max. cost perturbation = " << max_cost_correction;
728  return max_cost_correction;
729 }
730 
731 // This computes by how much the rhs must be perturbed to enforce the fact that
732 // the constraint activities exactly reflect their status.
733 Fractional LPSolver::ComputeMaxRhsPerturbationToEnforceOptimality(
734  const LinearProgram& lp, bool* is_too_large) {
735  Fractional max_rhs_correction = 0.0;
736  const RowIndex num_rows = lp.num_constraints();
737  const Fractional tolerance = parameters_.solution_feasibility_tolerance();
738  for (RowIndex row(0); row < num_rows; ++row) {
739  const Fractional lower_bound = lp.constraint_lower_bounds()[row];
740  const Fractional upper_bound = lp.constraint_upper_bounds()[row];
741  const Fractional activity = constraint_activities_[row];
742  const ConstraintStatus status = constraint_statuses_[row];
743 
744  Fractional rhs_error = 0.0;
745  Fractional allowed_error = 0.0;
746  if (status == ConstraintStatus::AT_LOWER_BOUND || activity < lower_bound) {
747  rhs_error = std::abs(activity - lower_bound);
748  allowed_error = AllowedError(tolerance, lower_bound);
749  } else if (status == ConstraintStatus::AT_UPPER_BOUND ||
750  activity > upper_bound) {
751  rhs_error = std::abs(activity - upper_bound);
752  allowed_error = AllowedError(tolerance, upper_bound);
753  }
754  max_rhs_correction = std::max(max_rhs_correction, rhs_error);
755  *is_too_large |= rhs_error > allowed_error;
756  }
757  VLOG(1) << "Max. rhs perturbation = " << max_rhs_correction;
758  return max_rhs_correction;
759 }
760 
761 void LPSolver::ComputeConstraintActivities(const LinearProgram& lp) {
762  const RowIndex num_rows = lp.num_constraints();
763  const ColIndex num_cols = lp.num_variables();
764  DCHECK_EQ(num_cols, primal_values_.size());
765  constraint_activities_.assign(num_rows, 0.0);
766  for (ColIndex col(0); col < num_cols; ++col) {
767  lp.GetSparseColumn(col).AddMultipleToDenseVector(primal_values_[col],
768  &constraint_activities_);
769  }
770 }
771 
772 void LPSolver::ComputeReducedCosts(const LinearProgram& lp) {
773  const RowIndex num_rows = lp.num_constraints();
774  const ColIndex num_cols = lp.num_variables();
775  DCHECK_EQ(num_rows, dual_values_.size());
776  reduced_costs_.resize(num_cols, 0.0);
777  for (ColIndex col(0); col < num_cols; ++col) {
778  reduced_costs_[col] = lp.objective_coefficients()[col] -
779  ScalarProduct(dual_values_, lp.GetSparseColumn(col));
780  }
781 }
782 
783 double LPSolver::ComputeObjective(const LinearProgram& lp) {
784  const ColIndex num_cols = lp.num_variables();
785  DCHECK_EQ(num_cols, primal_values_.size());
786  KahanSum sum;
787  for (ColIndex col(0); col < num_cols; ++col) {
788  sum.Add(lp.objective_coefficients()[col] * primal_values_[col]);
789  }
790  return sum.Value();
791 }
792 
793 // By the duality theorem, the dual "objective" is a bound on the primal
794 // objective obtained by taking the linear combinaison of the constraints
795 // given by dual_values_.
796 //
797 // As it is written now, this has no real precise meaning since we ignore
798 // infeasible reduced costs. This is almost the same as computing the objective
799 // to the perturbed problem, but then we don't use the pertubed rhs. It is just
800 // here as an extra "consistency" check.
801 //
802 // Note(user): We could actually compute an EXACT lower bound for the cost of
803 // the non-cost perturbed problem. The idea comes from "Safe bounds in linear
804 // and mixed-integer linear programming", Arnold Neumaier , Oleg Shcherbina,
805 // Math Prog, 2003. Note that this requires having some variable bounds that may
806 // not be in the original problem so that the current dual solution is always
807 // feasible. It also involves changing the rounding mode to obtain exact
808 // confidence intervals on the reduced costs.
809 double LPSolver::ComputeDualObjective(const LinearProgram& lp) {
810  KahanSum dual_objective;
811 
812  // Compute the part coming from the row constraints.
813  const RowIndex num_rows = lp.num_constraints();
814  const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
815  for (RowIndex row(0); row < num_rows; ++row) {
816  const Fractional lower_bound = lp.constraint_lower_bounds()[row];
817  const Fractional upper_bound = lp.constraint_upper_bounds()[row];
818 
819  // We correct the optimization_sign so we have to compute a lower bound.
820  const Fractional corrected_value = optimization_sign * dual_values_[row];
821  if (corrected_value > 0.0 && lower_bound != -kInfinity) {
822  dual_objective.Add(dual_values_[row] * lower_bound);
823  }
824  if (corrected_value < 0.0 && upper_bound != kInfinity) {
825  dual_objective.Add(dual_values_[row] * upper_bound);
826  }
827  }
828 
829  // For a given column associated to a variable x, we want to find a lower
830  // bound for c.x (where c is the objective coefficient for this column). If we
831  // write a.x the linear combination of the constraints at this column we have:
832  // (c + a - c) * x = a * x, and so
833  // c * x = a * x + (c - a) * x
834  // Now, if we suppose for example that the reduced cost 'c - a' is positive
835  // and that x is lower-bounded by 'lb' then the best bound we can get is
836  // c * x >= a * x + (c - a) * lb.
837  //
838  // Note: when summing over all variables, the left side is the primal
839  // objective and the right side is a lower bound to the objective. In
840  // particular, a necessary and sufficient condition for both objectives to be
841  // the same is that all the single variable inequalities above be equalities.
842  // This is possible only if c == a or if x is at its bound (modulo the
843  // optimization_sign of the reduced cost), or both (this is one side of the
844  // complementary slackness conditions, see Chvatal p. 62).
845  const ColIndex num_cols = lp.num_variables();
846  for (ColIndex col(0); col < num_cols; ++col) {
847  const Fractional lower_bound = lp.variable_lower_bounds()[col];
848  const Fractional upper_bound = lp.variable_upper_bounds()[col];
849 
850  // Correct the reduced cost, so as to have a minimization problem and
851  // thus a dual objective that is a lower bound of the primal objective.
852  const Fractional reduced_cost = optimization_sign * reduced_costs_[col];
853 
854  // We do not do any correction if the reduced cost is 'infeasible', which is
855  // the same as computing the objective of the perturbed problem.
856  Fractional correction = 0.0;
857  if (variable_statuses_[col] == VariableStatus::AT_LOWER_BOUND &&
858  reduced_cost > 0.0) {
859  correction = reduced_cost * lower_bound;
860  } else if (variable_statuses_[col] == VariableStatus::AT_UPPER_BOUND &&
861  reduced_cost < 0.0) {
862  correction = reduced_cost * upper_bound;
863  } else if (variable_statuses_[col] == VariableStatus::FIXED_VALUE) {
864  correction = reduced_cost * upper_bound;
865  }
866  // Now apply the correction in the right direction!
867  dual_objective.Add(optimization_sign * correction);
868  }
869  return dual_objective.Value();
870 }
871 
872 double LPSolver::ComputeMaxExpectedObjectiveError(const LinearProgram& lp) {
873  const ColIndex num_cols = lp.num_variables();
874  DCHECK_EQ(num_cols, primal_values_.size());
875  const Fractional tolerance = parameters_.solution_feasibility_tolerance();
876  Fractional primal_objective_error = 0.0;
877  for (ColIndex col(0); col < num_cols; ++col) {
878  // TODO(user): Be more precise since the non-BASIC variables are exactly at
879  // their bounds, so for them the error bound is just the term magnitude
880  // times std::numeric_limits<double>::epsilon() with KahanSum.
881  primal_objective_error += std::abs(lp.objective_coefficients()[col]) *
882  AllowedError(tolerance, primal_values_[col]);
883  }
884  return primal_objective_error;
885 }
886 
887 double LPSolver::ComputePrimalValueInfeasibility(const LinearProgram& lp,
888  bool* is_too_large) {
889  double infeasibility = 0.0;
890  const Fractional tolerance = parameters_.solution_feasibility_tolerance();
891  const ColIndex num_cols = lp.num_variables();
892  for (ColIndex col(0); col < num_cols; ++col) {
893  const Fractional lower_bound = lp.variable_lower_bounds()[col];
894  const Fractional upper_bound = lp.variable_upper_bounds()[col];
895  DCHECK(IsFinite(primal_values_[col]));
896 
897  if (lower_bound == upper_bound) {
898  const Fractional error = std::abs(primal_values_[col] - upper_bound);
899  infeasibility = std::max(infeasibility, error);
900  *is_too_large |= error > AllowedError(tolerance, upper_bound);
901  continue;
902  }
903  if (primal_values_[col] > upper_bound) {
904  const Fractional error = primal_values_[col] - upper_bound;
905  infeasibility = std::max(infeasibility, error);
906  *is_too_large |= error > AllowedError(tolerance, upper_bound);
907  }
908  if (primal_values_[col] < lower_bound) {
909  const Fractional error = lower_bound - primal_values_[col];
910  infeasibility = std::max(infeasibility, error);
911  *is_too_large |= error > AllowedError(tolerance, lower_bound);
912  }
913  }
914  return infeasibility;
915 }
916 
917 double LPSolver::ComputeActivityInfeasibility(const LinearProgram& lp,
918  bool* is_too_large) {
919  double infeasibility = 0.0;
920  int num_problematic_rows(0);
921  const RowIndex num_rows = lp.num_constraints();
922  const Fractional tolerance = parameters_.solution_feasibility_tolerance();
923  for (RowIndex row(0); row < num_rows; ++row) {
924  const Fractional activity = constraint_activities_[row];
925  const Fractional lower_bound = lp.constraint_lower_bounds()[row];
926  const Fractional upper_bound = lp.constraint_upper_bounds()[row];
927  DCHECK(IsFinite(activity));
928 
929  if (lower_bound == upper_bound) {
930  if (std::abs(activity - upper_bound) >
931  AllowedError(tolerance, upper_bound)) {
932  VLOG(2) << "Row " << row.value() << " has activity " << activity
933  << " which is different from " << upper_bound << " by "
934  << activity - upper_bound;
935  ++num_problematic_rows;
936  }
937  infeasibility = std::max(infeasibility, std::abs(activity - upper_bound));
938  continue;
939  }
940  if (activity > upper_bound) {
941  const Fractional row_excess = activity - upper_bound;
942  if (row_excess > AllowedError(tolerance, upper_bound)) {
943  VLOG(2) << "Row " << row.value() << " has activity " << activity
944  << ", exceeding its upper bound " << upper_bound << " by "
945  << row_excess;
946  ++num_problematic_rows;
947  }
948  infeasibility = std::max(infeasibility, row_excess);
949  }
950  if (activity < lower_bound) {
951  const Fractional row_deficit = lower_bound - activity;
952  if (row_deficit > AllowedError(tolerance, lower_bound)) {
953  VLOG(2) << "Row " << row.value() << " has activity " << activity
954  << ", below its lower bound " << lower_bound << " by "
955  << row_deficit;
956  ++num_problematic_rows;
957  }
958  infeasibility = std::max(infeasibility, row_deficit);
959  }
960  }
961  if (num_problematic_rows > 0) {
962  *is_too_large = true;
963  VLOG(1) << "Number of infeasible rows = " << num_problematic_rows;
964  }
965  return infeasibility;
966 }
967 
968 double LPSolver::ComputeDualValueInfeasibility(const LinearProgram& lp,
969  bool* is_too_large) {
970  const Fractional allowed_error = parameters_.solution_feasibility_tolerance();
971  const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
972  double infeasibility = 0.0;
973  const RowIndex num_rows = lp.num_constraints();
974  for (RowIndex row(0); row < num_rows; ++row) {
975  const Fractional dual_value = dual_values_[row];
976  const Fractional lower_bound = lp.constraint_lower_bounds()[row];
977  const Fractional upper_bound = lp.constraint_upper_bounds()[row];
978  DCHECK(IsFinite(dual_value));
979  const Fractional minimization_dual_value = optimization_sign * dual_value;
980  if (lower_bound == -kInfinity) {
981  *is_too_large |= minimization_dual_value > allowed_error;
982  infeasibility = std::max(infeasibility, minimization_dual_value);
983  }
984  if (upper_bound == kInfinity) {
985  *is_too_large |= -minimization_dual_value > allowed_error;
986  infeasibility = std::max(infeasibility, -minimization_dual_value);
987  }
988  }
989  return infeasibility;
990 }
991 
992 double LPSolver::ComputeReducedCostInfeasibility(const LinearProgram& lp,
993  bool* is_too_large) {
994  const Fractional optimization_sign = lp.IsMaximizationProblem() ? -1.0 : 1.0;
995  double infeasibility = 0.0;
996  const ColIndex num_cols = lp.num_variables();
997  const Fractional tolerance = parameters_.solution_feasibility_tolerance();
998  for (ColIndex col(0); col < num_cols; ++col) {
999  const Fractional reduced_cost = reduced_costs_[col];
1000  const Fractional lower_bound = lp.variable_lower_bounds()[col];
1001  const Fractional upper_bound = lp.variable_upper_bounds()[col];
1002  DCHECK(IsFinite(reduced_cost));
1003  const Fractional minimization_reduced_cost =
1004  optimization_sign * reduced_cost;
1005  const Fractional allowed_error =
1006  AllowedError(tolerance, lp.objective_coefficients()[col]);
1007  if (lower_bound == -kInfinity) {
1008  *is_too_large |= minimization_reduced_cost > allowed_error;
1009  infeasibility = std::max(infeasibility, minimization_reduced_cost);
1010  }
1011  if (upper_bound == kInfinity) {
1012  *is_too_large |= -minimization_reduced_cost > allowed_error;
1013  infeasibility = std::max(infeasibility, -minimization_reduced_cost);
1014  }
1015  }
1016  return infeasibility;
1017 }
1018 
1019 } // namespace glop
1020 } // namespace operations_research
operations_research::glop::ProblemStatus::PRIMAL_FEASIBLE
@ PRIMAL_FEASIBLE
operations_research::glop::LPSolver::GetMutableParameters
GlopParameters * GetMutableParameters()
Definition: lp_solver.cc:117
operations_research::glop::ConstraintStatus::FREE
@ FREE
operations_research::glop::VariableStatus::AT_UPPER_BOUND
@ AT_UPPER_BOUND
min
int64 min
Definition: alldiff_cst.cc:138
integral_types.h
operations_research::glop::VariableStatus::BASIC
@ BASIC
operations_research::glop::LPSolver::variable_statuses
const VariableStatusRow & variable_statuses() const
Definition: lp_solver.h:102
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::glop::LPSolver::SetParameters
void SetParameters(const GlopParameters &parameters)
Definition: lp_solver.cc:111
operations_research::glop::LPSolver::MayHaveMultipleOptimalSolutions
bool MayHaveMultipleOptimalSolutions() const
Definition: lp_solver.cc:456
operations_research::glop::ProblemStatus::ABNORMAL
@ ABNORMAL
operations_research::glop::LinearProgram::constraint_upper_bounds
const DenseColumn & constraint_upper_bounds() const
Definition: lp_data.h:218
operations_research::glop::StrictITIVector< ColIndex, VariableStatus >
operations_research::glop::ProblemStatus::IMPRECISE
@ IMPRECISE
file_util.h
operations_research::glop::KahanSum
AccurateSum< Fractional > KahanSum
Definition: lp_data/lp_utils.h:32
operations_research::glop::LinearProgram::variable_lower_bounds
const DenseRow & variable_lower_bounds() const
Definition: lp_data.h:229
operations_research::glop::LinearProgram::variable_upper_bounds
const DenseRow & variable_upper_bounds() const
Definition: lp_data.h:232
operations_research::ProtoWriteFormat::kProtoText
@ kProtoText
operations_research::glop::ConstraintStatus::FIXED_VALUE
@ FIXED_VALUE
operations_research::glop::LPSolver::GetNumberOfSimplexIterations
int GetNumberOfSimplexIterations() const
Definition: lp_solver.cc:460
proto_utils.h
operations_research::glop::LinearProgramToMPModelProto
void LinearProgramToMPModelProto(const LinearProgram &input, MPModelProto *output)
Definition: proto_utils.cc:20
operations_research::AreWithinAbsoluteTolerance
bool AreWithinAbsoluteTolerance(FloatType x, FloatType y, FloatType absolute_tolerance)
Definition: fp_utils.h:140
operations_research::glop::StrictITIVector::assign
void assign(IntType size, const T &v)
Definition: lp_types.h:274
operations_research::AccurateSum::Add
void Add(const FpNumber &value)
Definition: accurate_sum.h:29
value
int64 value
Definition: demon_profiler.cc:43
operations_research::glop::ProblemSolution
Definition: lp_data.h:647
lp_utils.h
operations_research::glop::Preprocessor::SetTimeLimit
void SetTimeLimit(TimeLimit *time_limit)
Definition: preprocessor.h:74
operations_research::glop::LinearProgram::IsValid
bool IsValid() const
Definition: lp_data.cc:1237
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::glop::LinearProgram::constraint_lower_bounds
const DenseColumn & constraint_lower_bounds() const
Definition: lp_data.h:215
operations_research::glop::ConstraintStatus
ConstraintStatus
Definition: lp_types.h:227
operations_research::glop::LinearProgram::IsCleanedUp
bool IsCleanedUp() const
Definition: lp_data.cc:352
operations_research::glop::LinearProgram
Definition: lp_data.h:55
operations_research::glop::StrictITIVector::resize
void resize(IntType size)
Definition: lp_types.h:269
operations_research::glop::ProblemStatus::INVALID_PROBLEM
@ INVALID_PROBLEM
operations_research::glop::LinearProgram::GetObjectiveStatsString
std::string GetObjectiveStatsString() const
Definition: lp_data.cc:431
operations_research::glop::LinearProgram::num_variables
ColIndex num_variables() const
Definition: lp_data.h:205
operations_research::glop::Fractional
double Fractional
Definition: lp_types.h:77
operations_research::glop::ConstraintStatus::AT_UPPER_BOUND
@ AT_UPPER_BOUND
operations_research::glop::MainLpPreprocessor::RecoverSolution
void RecoverSolution(ProblemSolution *solution) const override
Definition: preprocessor.cc:173
DEFINE_int32
DEFINE_int32(lp_dump_file_number, -1, "Number for the dump file, in the form name-000048.pb. " "If < 0, the file is automatically numbered from the number of " "calls to LPSolver::Solve().")
DEFINE_string
DEFINE_string(lp_dump_dir, "/tmp", "Directory where dump files are written.")
operations_research::glop::BasisState
Definition: revised_simplex.h:132
operations_research::glop::VariableStatus::FIXED_VALUE
@ FIXED_VALUE
operations_research::glop::LPSolver::LPSolver
LPSolver()
Definition: lp_solver.cc:109
operations_research::glop::LinearProgram::PopulateFromLinearProgram
void PopulateFromLinearProgram(const LinearProgram &linear_program)
Definition: lp_data.cc:831
operations_research::glop::kInfinity
const double kInfinity
Definition: lp_types.h:83
operations_research::glop::LinearProgram::GetDimensionString
std::string GetDimensionString() const
Definition: lp_data.cc:423
operations_research::glop::ScalarProduct
Fractional ScalarProduct(const DenseRowOrColumn1 &u, const DenseRowOrColumn2 &v)
Definition: lp_data/lp_utils.h:47
operations_research::glop::LPSolver::Clear
void Clear()
Definition: lp_solver.cc:211
operations_research::glop::MainLpPreprocessor::Run
bool Run(LinearProgram *lp) final
Definition: preprocessor.cc:61
operations_research::glop::BasisState::statuses
VariableStatusRow statuses
Definition: revised_simplex.h:140
operations_research::glop::LPSolver::Solve
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
Definition: lp_solver.cc:119
operations_research::glop::ProblemSolution::primal_values
DenseRow primal_values
Definition: lp_data.h:659
operations_research::glop::Preprocessor::status
ProblemStatus status() const
Definition: preprocessor.h:64
time_limit
SharedTimeLimit * time_limit
Definition: cp_model_solver.cc:2025
operations_research::glop::IsFinite
bool IsFinite(Fractional value)
Definition: lp_types.h:90
DEFINE_bool
DEFINE_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.")
operations_research::glop::GetVariableStatusString
std::string GetVariableStatusString(VariableStatus status)
Definition: lp_types.cc:71
timer.h
operations_research::TimeLimit
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:105
fp_utils.h
operations_research::glop::StrictITIVector::size
IntType size() const
Definition: lp_types.h:276
operations_research::ProtoWriteFormat::kProtoBinary
@ kProtoBinary
operations_research::WriteProtoToFile
bool WriteProtoToFile(absl::string_view filename, const google::protobuf::Message &proto, ProtoWriteFormat proto_write_format, bool gzipped, bool append_extension_to_file_name)
Definition: file_util.cc:76
operations_research::glop::MainLpPreprocessor
Definition: preprocessor.h:102
operations_research::ProtoWriteFormat
ProtoWriteFormat
Definition: file_util.h:47
operations_research::glop::LinearProgram::ClearTransposeMatrix
void ClearTransposeMatrix()
Definition: lp_data.cc:402
operations_research::glop::ConstraintStatus::BASIC
@ BASIC
operations_research::glop::ProblemSolution::dual_values
DenseColumn dual_values
Definition: lp_data.h:660
operations_research::glop::LPSolver::constraint_statuses
const ConstraintStatusColumn & constraint_statuses() const
Definition: lp_solver.h:116
operations_research::glop::LinearProgram::objective_offset
Fractional objective_offset() const
Definition: lp_data.h:260
operations_research::glop::ProblemSolution::variable_statuses
VariableStatusRow variable_statuses
Definition: lp_data.h:675
operations_research::glop::LPSolver::GetMaximumDualInfeasibility
Fractional GetMaximumDualInfeasibility() const
Definition: lp_solver.cc:452
operations_research::glop::LPSolver::SolveWithTimeLimit
ABSL_MUST_USE_RESULT ProblemStatus SolveWithTimeLimit(const LinearProgram &lp, TimeLimit *time_limit)
Definition: lp_solver.cc:125
operations_research::glop::LPSolver::GetMaximumPrimalInfeasibility
Fractional GetMaximumPrimalInfeasibility() const
Definition: lp_solver.cc:448
operations_research::glop::LPSolver::SetInitialBasis
void SetInitialBasis(const VariableStatusRow &variable_statuses, const ConstraintStatusColumn &constraint_statuses)
Definition: lp_solver.cc:216
operations_research::glop::LinearProgram::num_constraints
RowIndex num_constraints() const
Definition: lp_data.h:208
operations_research::glop::LinearProgram::objective_scaling_factor
Fractional objective_scaling_factor() const
Definition: lp_data.h:261
operations_research::glop::ProblemStatus::OPTIMAL
@ OPTIMAL
col
ColIndex col
Definition: markowitz.cc:176
operations_research::glop::LPSolver::LoadAndVerifySolution
ProblemStatus LoadAndVerifySolution(const LinearProgram &lp, const ProblemSolution &solution)
Definition: lp_solver.cc:270
operations_research::glop::ProblemStatus
ProblemStatus
Definition: lp_types.h:101
row
RowIndex row
Definition: markowitz.cc:175
operations_research::glop::ConstraintStatus::AT_LOWER_BOUND
@ AT_LOWER_BOUND
operations_research::glop::ProblemStatus::INIT
@ INIT
operations_research::glop::LPSolver::DeterministicTime
double DeterministicTime() const
Definition: lp_solver.cc:464
operations_research::glop::ProblemStatus::DUAL_FEASIBLE
@ DUAL_FEASIBLE
gtl::ITIVector::push_back
void push_back(const value_type &x)
Definition: int_type_indexed_vector.h:157
proto
CpModelProto proto
Definition: cp_model_fz_solver.cc:106
operations_research::glop::VariableStatus
VariableStatus
Definition: lp_types.h:196
operations_research::glop::VariableStatus::FREE
@ FREE
operations_research::glop::ProblemSolution::status
ProblemStatus status
Definition: lp_data.h:655
lp_types.h
operations_research::TimeLimit::FromParameters
static std::unique_ptr< TimeLimit > FromParameters(const Parameters &parameters)
Creates a time limit object initialized from an object that provides methods max_time_in_seconds() an...
Definition: time_limit.h:159
operations_research::glop::LPSolver::GetParameters
const GlopParameters & GetParameters() const
Definition: lp_solver.cc:115
operations_research::glop::LPSolver::GetObjectiveValue
Fractional GetObjectiveValue() const
Definition: lp_solver.cc:444
operations_research::glop::ProblemSolution::constraint_statuses
ConstraintStatusColumn constraint_statuses
Definition: lp_data.h:676
preprocessor.h
operations_research::ScopedFloatingPointEnv
Definition: fp_utils.h:60
commandlineflags.h
parameters
SatParameters parameters
Definition: cp_model_fz_solver.cc:107
status.h
operations_research::glop::GetConstraintStatusString
std::string GetConstraintStatusString(ConstraintStatus status)
Definition: lp_types.cc:90
lp_solver.h
operations_research::ScopedFloatingPointEnv::EnableExceptions
void EnableExceptions(int excepts)
Definition: fp_utils.h:78
operations_research::glop::VariableStatus::AT_LOWER_BOUND
@ AT_LOWER_BOUND