OR-Tools  9.6
revised_simplex.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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 // Solves a Linear Programming problem using the Revised Simplex algorithm
15 // as described by G.B. Dantzig.
16 // The general form is:
17 // min c.x where c and x are n-vectors,
18 // subject to Ax = b where A is an mxn-matrix, b an m-vector,
19 // with l <= x <= u, i.e.
20 // l_i <= x_i <= u_i for all i in {1 .. m}.
21 //
22 // c.x is called the objective function.
23 // Each row a_i of A is an n-vector, and a_i.x = b_i is a linear constraint.
24 // A is called the constraint matrix.
25 // b is called the right hand side (rhs) of the problem.
26 // The constraints l_i <= x_i <= u_i are called the generalized bounds
27 // of the problem (most introductory textbooks only deal with x_i >= 0, as
28 // did the first version of the Simplex algorithm). Note that l_i and u_i
29 // can be -infinity and +infinity, respectively.
30 //
31 // To simplify the entry of data, this code actually handles problems in the
32 // form:
33 // min c.x where c and x are n-vectors,
34 // subject to:
35 // A1 x <= b1
36 // A2 x >= b2
37 // A3 x = b3
38 // l <= x <= u
39 //
40 // It transforms the above problem into
41 // min c.x where c and x are n-vectors,
42 // subject to:
43 // A1 x + s1 = b1
44 // A2 x - s2 = b2
45 // A3 x = b3
46 // l <= x <= u
47 // s1 >= 0, s2 >= 0
48 // where xT = (x1, x2, x3),
49 // s1 is an m1-vector (m1 being the height of A1),
50 // s2 is an m2-vector (m2 being the height of A2).
51 //
52 // The following are very good references for terminology, data structures,
53 // and algorithms. They all contain a wealth of references.
54 //
55 // Vasek Chvátal, "Linear Programming," W.H. Freeman, 1983. ISBN 978-0716715870.
56 // http://www.amazon.com/dp/0716715872
57 //
58 // Robert J. Vanderbei, "Linear Programming: Foundations and Extensions,"
59 // Springer, 2010, ISBN-13: 978-1441944979
60 // http://www.amazon.com/dp/1441944974
61 //
62 // Istvan Maros, "Computational Techniques of the Simplex Method.", Springer,
63 // 2002, ISBN 978-1402073328
64 // http://www.amazon.com/dp/1402073321
65 //
66 // ===============================================
67 // Short description of the dual simplex algorithm.
68 //
69 // The dual simplex algorithm uses the same data structure as the primal, but
70 // progresses towards the optimal solution in a different way:
71 // * It tries to keep the dual values dual-feasible at all time which means that
72 // the reduced costs are of the correct sign depending on the bounds of the
73 // non-basic variables. As a consequence the values of the basic variable are
74 // out of bound until the optimal is reached.
75 // * A basic leaving variable is selected first (dual pricing) and then a
76 // corresponding entering variable is selected. This is done in such a way
77 // that the dual objective value increases (lower bound on the optimal
78 // solution).
79 // * Once the basis pivot is chosen, the variable values and the reduced costs
80 // are updated the same way as in the primal algorithm.
81 //
82 // Good references on the Dual simplex algorithm are:
83 //
84 // Robert Fourer, "Notes on the Dual simplex Method", March 14, 1994.
85 // http://users.iems.northwestern.edu/~4er/WRITINGS/dual.pdf
86 //
87 // Achim Koberstein, "The dual simplex method, techniques for a fast and stable
88 // implementation", PhD, Paderborn, Univ., 2005.
89 // http://digital.ub.uni-paderborn.de/hs/download/pdf/3885?originalFilename=true
90 
91 #ifndef OR_TOOLS_GLOP_REVISED_SIMPLEX_H_
92 #define OR_TOOLS_GLOP_REVISED_SIMPLEX_H_
93 
94 #include <cstdint>
95 #include <string>
96 #include <vector>
97 
98 #include "absl/random/bit_gen_ref.h"
100 #include "ortools/base/macros.h"
104 #include "ortools/glop/parameters.pb.h"
105 #include "ortools/glop/pricing.h"
108 #include "ortools/glop/status.h"
109 #include "ortools/glop/update_row.h"
112 #include "ortools/lp_data/lp_data.h"
117 #include "ortools/util/logging.h"
119 #include "ortools/util/time_limit.h"
120 
121 namespace operations_research {
122 namespace glop {
123 
124 // Entry point of the revised simplex algorithm implementation.
126  public:
127  RevisedSimplex();
128 
129  // Sets or gets the algorithm parameters to be used on the next Solve().
130  void SetParameters(const GlopParameters& parameters);
131  const GlopParameters& GetParameters() const { return parameters_; }
132 
133  // Solves the given linear program.
134  //
135  // We accept two forms of LinearProgram:
136  // - The lp can be in the equations form Ax = 0 created by
137  // LinearProgram::AddSlackVariablesForAllRows(), i.e. the rightmost square
138  // submatrix of A is an identity matrix, all its columns have been marked as
139  // slack variables, and the bounds of all constraints have been set to 0.
140  // - If not, we will convert it internally while copying it to the internal
141  // structure used.
142  //
143  // By default, the algorithm tries to exploit the computation done during the
144  // last Solve() call. It will analyze the difference of the new linear program
145  // and try to use the previously computed solution as a warm-start. To disable
146  // this behavior or give explicit warm-start data, use one of the State*()
147  // functions below.
148  ABSL_MUST_USE_RESULT Status Solve(const LinearProgram& lp,
150 
151  // Do not use the current solution as a warm-start for the next Solve(). The
152  // next Solve() will behave as if the class just got created.
153  void ClearStateForNextSolve();
154 
155  // Uses the given state as a warm-start for the next Solve() call.
156  void LoadStateForNextSolve(const BasisState& state);
157 
158  // Advanced usage. While constructing the initial basis, if this is called
159  // then we will use these values as the initial starting value for the FREE
160  // variables.
162 
163  // Advanced usage. Tells the next Solve() that the matrix inside the linear
164  // program will not change compared to the one used the last time Solve() was
165  // called. This allows to bypass the somewhat costly check of comparing both
166  // matrices. Note that this call will be ignored if Solve() was never called
167  // or if ClearStateForNextSolve() was called.
170 
171  // Getters to retrieve all the information computed by the last Solve().
172  RowIndex GetProblemNumRows() const;
173  ColIndex GetProblemNumCols() const;
176  int64_t GetNumberOfIterations() const;
177  Fractional GetVariableValue(ColIndex col) const;
178  Fractional GetReducedCost(ColIndex col) const;
179  const DenseRow& GetReducedCosts() const;
180  Fractional GetDualValue(RowIndex row) const;
181  Fractional GetConstraintActivity(RowIndex row) const;
182  VariableStatus GetVariableStatus(ColIndex col) const;
183  ConstraintStatus GetConstraintStatus(RowIndex row) const;
184  const BasisState& GetState() const;
185  double DeterministicTime() const;
186  bool objective_limit_reached() const { return objective_limit_reached_; }
187 
188  // If the problem status is PRIMAL_UNBOUNDED (respectively DUAL_UNBOUNDED),
189  // then the solver has a corresponding primal (respectively dual) ray to show
190  // the unboundness. From a primal (respectively dual) feasible solution any
191  // positive multiple of this ray can be added to the solution and keep it
192  // feasible. Moreover, by doing so, the objective of the problem will improve
193  // and its magnitude will go to infinity.
194  //
195  // Note that when the problem is DUAL_UNBOUNDED, the dual ray is also known as
196  // the Farkas proof of infeasibility of the problem.
197  const DenseRow& GetPrimalRay() const;
198  const DenseColumn& GetDualRay() const;
199 
200  // This is the "dual ray" linear combination of the matrix rows.
201  const DenseRow& GetDualRayRowCombination() const;
202 
203  // Returns the index of the column in the basis and the basis factorization.
204  // Note that the order of the column in the basis is important since it is the
205  // one used by the various solve functions provided by the BasisFactorization
206  // class.
207  ColIndex GetBasis(RowIndex row) const;
208 
210  return update_row_.ComputeAndGetUnitRowLeftInverse(row);
211  }
212 
213  // Returns a copy of basis_ vector for outside applications (like cuts) to
214  // have the correspondence between rows and columns of the dictionary.
215  RowToColMapping GetBasisVector() const { return basis_; }
216 
218 
219  // Returns statistics about this class as a string.
220  std::string StatString();
221 
222  // Computes the dictionary B^-1*N on-the-fly row by row. Returns the resulting
223  // matrix as a vector of sparse rows so that it is easy to use it on the left
224  // side in the matrix multiplication. Runs in O(num_non_zeros_in_matrix).
225  // TODO(user): Use row scales as well.
226  RowMajorSparseMatrix ComputeDictionary(const DenseRow* column_scales);
227 
228  // Initializes the matrix for the given 'linear_program' and 'state' and
229  // computes the variable values for basic variables using non-basic variables.
230  void ComputeBasicVariablesForState(const LinearProgram& linear_program,
231  const BasisState& state);
232 
233  // This is used in a MIP context to polish the final basis. We assume that the
234  // columns for which SetIntegralityScale() has been called correspond to
235  // integral variable once multiplied by the given factor.
236  void ClearIntegralityScales() { integrality_scale_.clear(); }
237  void SetIntegralityScale(ColIndex col, Fractional scale);
238 
239  void SetLogger(SolverLogger* logger) { logger_ = logger; }
240 
241  private:
242  struct IterationStats : public StatsGroup {
243  IterationStats()
244  : StatsGroup("IterationStats"),
245  total("total", this),
246  normal("normal", this),
247  bound_flip("bound_flip", this),
248  refactorize("refactorize", this),
249  degenerate("degenerate", this),
250  num_dual_flips("num_dual_flips", this),
251  degenerate_run_size("degenerate_run_size", this) {}
252  TimeDistribution total;
253  TimeDistribution normal;
254  TimeDistribution bound_flip;
255  TimeDistribution refactorize;
256  TimeDistribution degenerate;
257  IntegerDistribution num_dual_flips;
258  IntegerDistribution degenerate_run_size;
259  };
260 
261  struct RatioTestStats : public StatsGroup {
262  RatioTestStats()
263  : StatsGroup("RatioTestStats"),
264  bound_shift("bound_shift", this),
265  abs_used_pivot("abs_used_pivot", this),
266  abs_tested_pivot("abs_tested_pivot", this),
267  abs_skipped_pivot("abs_skipped_pivot", this),
268  direction_density("direction_density", this),
269  leaving_choices("leaving_choices", this),
270  num_perfect_ties("num_perfect_ties", this) {}
271  DoubleDistribution bound_shift;
272  DoubleDistribution abs_used_pivot;
273  DoubleDistribution abs_tested_pivot;
274  DoubleDistribution abs_skipped_pivot;
275  RatioDistribution direction_density;
276  IntegerDistribution leaving_choices;
277  IntegerDistribution num_perfect_ties;
278  };
279 
280  enum class Phase { FEASIBILITY, OPTIMIZATION, PUSH };
281 
282  enum class RefactorizationReason {
283  DEFAULT,
284  SMALL_PIVOT,
285  IMPRECISE_PIVOT,
286  NORM,
287  RC,
288  VAR_VALUES,
289  FINAL_CHECK
290  };
291 
292  // Propagates parameters_ to all the other classes that need it.
293  //
294  // TODO(user): Maybe a better design is for them to have a reference to a
295  // unique parameters object? It will clutter a bit more these classes'
296  // constructor though.
297  void PropagateParameters();
298 
299  // Returns a string containing the same information as with GetSolverStats,
300  // but in a much more human-readable format. For example:
301  // Problem status : Optimal
302  // Solving time : 1.843
303  // Number of iterations : 12345
304  // Time for solvability (first phase) : 1.343
305  // Number of iterations for solvability : 10000
306  // Time for optimization : 0.5
307  // Number of iterations for optimization : 2345
308  // Maximum time allowed in seconds : 6000
309  // Maximum number of iterations : 1000000
310  // Stop after first basis : 0
311  std::string GetPrettySolverStats() const;
312 
313  // Returns a string containing formatted information about the variable
314  // corresponding to column col.
315  std::string SimpleVariableInfo(ColIndex col) const;
316 
317  // Displays a short string with the current iteration and objective value.
318  void DisplayIterationInfo(bool primal, RefactorizationReason reason =
319  RefactorizationReason::DEFAULT);
320 
321  // Displays the error bounds of the current solution.
322  void DisplayErrors();
323 
324  // Displays the status of the variables.
325  void DisplayInfoOnVariables() const;
326 
327  // Displays the bounds of the variables.
328  void DisplayVariableBounds();
329 
330  // Displays the following information:
331  // * Linear Programming problem as a dictionary, taking into
332  // account the iterations that have been made;
333  // * Variable info;
334  // * Reduced costs;
335  // * Variable bounds.
336  // A dictionary is in the form:
337  // xB = value + sum_{j in N} pa_ij x_j
338  // z = objective_value + sum_{i in N} rc_i x_i
339  // where the pa's are the coefficients of the matrix after the pivotings
340  // and the rc's are the reduced costs, i.e. the coefficients of the objective
341  // after the pivotings.
342  // Dictionaries are the modern way of presenting the result of an iteration
343  // of the Simplex algorithm in the literature.
344  void DisplayRevisedSimplexDebugInfo();
345 
346  // Displays the Linear Programming problem as it was input.
347  void DisplayProblem() const;
348 
349  // Returns the current objective value. This is just the sum of the current
350  // variable values times their current cost.
351  Fractional ComputeObjectiveValue() const;
352 
353  // Returns the current objective of the linear program given to Solve() using
354  // the initial costs, maximization direction, objective offset and objective
355  // scaling factor.
356  Fractional ComputeInitialProblemObjectiveValue() const;
357 
358  // Assigns names to variables. Variables in the input will be named
359  // x1..., slack variables will be s1... .
360  void SetVariableNames();
361 
362  // Sets the variable status and derives the variable value according to the
363  // exact status definition. This can only be called for non-basic variables
364  // because the value of a basic variable is computed from the values of the
365  // non-basic variables.
366  void SetNonBasicVariableStatusAndDeriveValue(ColIndex col,
368 
369  // Checks if the basis_ and is_basic_ arrays are well formed. Also checks that
370  // the variable statuses are consistent with this basis. Returns true if this
371  // is the case. This is meant to be used in debug mode only.
372  bool BasisIsConsistent() const;
373 
374  // Moves the column entering_col into the basis at position basis_row. Removes
375  // the current basis column at position basis_row from the basis and sets its
376  // status to leaving_variable_status.
377  void UpdateBasis(ColIndex entering_col, RowIndex basis_row,
378  VariableStatus leaving_variable_status);
379 
380  // Initializes matrix-related internal data. Returns true if this data was
381  // unchanged. If not, also sets only_change_is_new_rows to true if compared
382  // to the current matrix, the only difference is that new rows have been
383  // added (with their corresponding extra slack variables). Similarly, sets
384  // only_change_is_new_cols to true if the only difference is that new columns
385  // have been added, in which case also sets num_new_cols to the number of
386  // new columns.
387  bool InitializeMatrixAndTestIfUnchanged(const LinearProgram& lp,
388  bool lp_is_in_equation_form,
389  bool* only_change_is_new_rows,
390  bool* only_change_is_new_cols,
391  ColIndex* num_new_cols);
392 
393  // Checks if the only change to the bounds is the addition of new columns,
394  // and that the new columns have at least one bound equal to zero.
395  bool OldBoundsAreUnchangedAndNewVariablesHaveOneBoundAtZero(
396  const LinearProgram& lp, bool lp_is_in_equation_form,
397  ColIndex num_new_cols);
398 
399  // Initializes objective-related internal data. Returns true if unchanged.
400  bool InitializeObjectiveAndTestIfUnchanged(const LinearProgram& lp);
401 
402  // Computes the stopping criterion on the problem objective value.
403  void InitializeObjectiveLimit(const LinearProgram& lp);
404 
405  // Initializes the starting basis. In most cases it starts by the all slack
406  // basis and tries to apply some heuristics to replace fixed variables.
407  ABSL_MUST_USE_RESULT Status CreateInitialBasis();
408 
409  // Sets the initial basis to the given columns, try to factorize it and
410  // recompute the basic variable values.
411  ABSL_MUST_USE_RESULT Status
412  InitializeFirstBasis(const RowToColMapping& initial_basis);
413 
414  // Entry point for the solver initialization.
415  ABSL_MUST_USE_RESULT Status Initialize(const LinearProgram& lp);
416 
417  // Saves the current variable statuses in solution_state_.
418  void SaveState();
419 
420  // Displays statistics on what kinds of variables are in the current basis.
421  void DisplayBasicVariableStatistics();
422 
423  // Tries to reduce the initial infeasibility (stored in error_) by using the
424  // singleton columns present in the problem. A singleton column is a column
425  // with only one non-zero. This is used by CreateInitialBasis().
426  void UseSingletonColumnInInitialBasis(RowToColMapping* basis);
427 
428  // Returns the number of empty rows in the matrix, i.e. rows where all
429  // the coefficients are zero.
430  RowIndex ComputeNumberOfEmptyRows();
431 
432  // Returns the number of empty columns in the matrix, i.e. columns where all
433  // the coefficients are zero.
434  ColIndex ComputeNumberOfEmptyColumns();
435 
436  // Returns the number of super-basic variables. These are non-basic variables
437  // that are not at their bounds (if they have bounds), or non-basic free
438  // variables that are not at zero.
439  int ComputeNumberOfSuperBasicVariables() const;
440 
441  // This method transforms a basis for the first phase, with the optimal
442  // value at zero, into a feasible basis for the initial problem, thus
443  // preparing the execution of phase-II of the algorithm.
444  void CleanUpBasis();
445 
446  // If the primal maximum residual is too large, recomputes the basic variable
447  // value from the non-basic ones. This function also perturbs the bounds
448  // during the primal simplex if too many iterations are degenerate.
449  //
450  // Only call this on a refactorized basis to have the best precision.
451  void CorrectErrorsOnVariableValues();
452 
453  // Computes b - A.x in error_
454  void ComputeVariableValuesError();
455 
456  // Solves the system B.d = a where a is the entering column (given by col).
457  // Known as FTRAN (Forward transformation) in FORTRAN codes.
458  // See Chvatal's book for more detail (Chapter 7).
459  void ComputeDirection(ColIndex col);
460 
461  // Computes a - B.d in error_ and return the maximum std::abs() of its coeffs.
462  Fractional ComputeDirectionError(ColIndex col);
463 
464  // Computes the ratio of the basic variable corresponding to 'row'. A target
465  // bound (upper or lower) is chosen depending on the sign of the entering
466  // reduced cost and the sign of the direction 'd_[row]'. The ratio is such
467  // that adding 'ratio * d_[row]' to the variable value changes it to its
468  // target bound.
469  template <bool is_entering_reduced_cost_positive>
470  Fractional GetRatio(const DenseRow& lower_bounds,
471  const DenseRow& upper_bounds, RowIndex row) const;
472 
473  // First pass of the Harris ratio test. Returns the harris ratio value which
474  // is an upper bound on the ratio value that the leaving variable can take.
475  // Fills leaving_candidates with the ratio and row index of a super-set of the
476  // columns with a ratio <= harris_ratio.
477  template <bool is_entering_reduced_cost_positive>
478  Fractional ComputeHarrisRatioAndLeavingCandidates(
479  Fractional bound_flip_ratio, SparseColumn* leaving_candidates) const;
480 
481  // Chooses the leaving variable, considering the entering column and its
482  // associated reduced cost. If there was a precision issue and the basis is
483  // not refactorized, set refactorize to true. Otherwise, the row number of the
484  // leaving variable is written in *leaving_row, and the step length
485  // is written in *step_length.
486  Status ChooseLeavingVariableRow(ColIndex entering_col,
487  Fractional reduced_cost, bool* refactorize,
488  RowIndex* leaving_row,
489  Fractional* step_length,
491 
492  // Chooses the leaving variable for the primal phase-I algorithm. The
493  // algorithm follows more or less what is described in Istvan Maros's book in
494  // chapter 9.6 and what is done for the dual phase-I algorithm which was
495  // derived from Koberstein's PhD. Both references can be found at the top of
496  // this file.
497  void PrimalPhaseIChooseLeavingVariableRow(ColIndex entering_col,
498  Fractional reduced_cost,
499  bool* refactorize,
500  RowIndex* leaving_row,
501  Fractional* step_length,
502  Fractional* target_bound) const;
503 
504  // Chooses an infeasible basic variable. The returned values are:
505  // - leaving_row: the basic index of the infeasible leaving variable
506  // or kNoLeavingVariable if no such row exists: the dual simplex algorithm
507  // has terminated and the optimal has been reached.
508  // - cost_variation: how much do we improve the objective by moving one unit
509  // along this dual edge.
510  // - target_bound: the bound at which the leaving variable should go when
511  // leaving the basis.
512  ABSL_MUST_USE_RESULT Status DualChooseLeavingVariableRow(
513  RowIndex* leaving_row, Fractional* cost_variation,
515 
516  // Updates the prices used by DualChooseLeavingVariableRow() after a simplex
517  // iteration by using direction_. The prices are stored in
518  // dual_pricing_vector_. Note that this function only takes care of the
519  // entering and leaving column dual feasibility status change and that other
520  // changes will be dealt with by DualPhaseIUpdatePriceOnReducedCostsChange().
521  void DualPhaseIUpdatePrice(RowIndex leaving_row, ColIndex entering_col);
522 
523  // This must be called each time the dual_pricing_vector_ is changed at
524  // position row.
525  template <bool use_dense_update = false>
526  void OnDualPriceChange(const DenseColumn& squared_norms, RowIndex row,
527  VariableType type, Fractional threshold);
528 
529  // Updates the prices used by DualChooseLeavingVariableRow() when the reduced
530  // costs of the given columns have changed.
531  template <typename Cols>
532  void DualPhaseIUpdatePriceOnReducedCostChange(const Cols& cols);
533 
534  // Same as DualChooseLeavingVariableRow() but for the phase I of the dual
535  // simplex. Here the objective is not to minimize the primal infeasibility,
536  // but the dual one, so the variable is not chosen in the same way. See
537  // "Notes on the Dual simplex Method" or Istvan Maros, "A Piecewise Linear
538  // Dual Phase-1 Algorithm for the Simplex Method", Computational Optimization
539  // and Applications, October 2003, Volume 26, Issue 1, pp 63-81.
540  // http://rd.springer.com/article/10.1023%2FA%3A1025102305440
541  ABSL_MUST_USE_RESULT Status DualPhaseIChooseLeavingVariableRow(
542  RowIndex* leaving_row, Fractional* cost_variation,
544 
545  // Makes sure the boxed variable are dual-feasible by setting them to the
546  // correct bound according to their reduced costs. This is called
547  // Dual feasibility correction in the literature.
548  //
549  // Note that this function is also used as a part of the bound flipping ratio
550  // test by flipping the boxed dual-infeasible variables at each iteration.
551  //
552  // If update_basic_values is true, the basic variable values are updated.
553  template <typename BoxedVariableCols>
554  void MakeBoxedVariableDualFeasible(const BoxedVariableCols& cols,
555  bool update_basic_values);
556 
557  // Computes the step needed to move the leaving_row basic variable to the
558  // given target bound.
559  Fractional ComputeStepToMoveBasicVariableToBound(RowIndex leaving_row,
561 
562  // Returns true if the basis obtained after the given pivot can be factorized.
563  bool TestPivot(ColIndex entering_col, RowIndex leaving_row);
564 
565  // Gets the current LU column permutation from basis_representation,
566  // applies it to basis_ and then sets it to the identity permutation since
567  // it will no longer be needed during solves. This function also updates all
568  // the data that depends on the column order in basis_.
569  void PermuteBasis();
570 
571  // Updates the system state according to the given basis pivot.
572  // Returns an error if the update could not be done because of some precision
573  // issue.
574  ABSL_MUST_USE_RESULT Status UpdateAndPivot(ColIndex entering_col,
575  RowIndex leaving_row,
577 
578  // Displays all the timing stats related to the calling object.
579  void DisplayAllStats();
580 
581  // Calls basis_factorization_.Refactorize() if refactorize is true, and
582  // returns its status. This also sets refactorize to false and invalidates any
583  // data structure that depends on the current factorization.
584  //
585  // The general idea is that if a refactorization is going to be needed during
586  // a simplex iteration, it is better to do it as soon as possible so that
587  // every component can take advantage of it.
588  Status RefactorizeBasisIfNeeded(bool* refactorize);
589 
590  // Main iteration loop of the primal simplex.
591  ABSL_MUST_USE_RESULT Status PrimalMinimize(TimeLimit* time_limit);
592 
593  // Main iteration loop of the dual simplex.
594  ABSL_MUST_USE_RESULT Status DualMinimize(bool feasibility_phase,
595  TimeLimit* time_limit);
596 
597  // Pushes all super-basic variables to bounds (if applicable) or to zero (if
598  // unconstrained). This is part of a "crossover" procedure to find a vertex
599  // solution given a (near) optimal solution. Assumes that Minimize() or
600  // DualMinimize() has already run, i.e., that we are at an optimal solution
601  // within numerical tolerances.
602  ABSL_MUST_USE_RESULT Status PrimalPush(TimeLimit* time_limit);
603 
604  // Experimental. This is useful in a MIP context. It performs a few degenerate
605  // pivot to try to mimize the fractionality of the optimal basis.
606  //
607  // We assume that the columns for which SetIntegralityScale() has been called
608  // correspond to integral variable once scaled by the given factor.
609  //
610  // I could only find slides for the reference of this "LP Solution Polishing
611  // to improve MIP Performance", Matthias Miltenberger, Zuse Institute Berlin.
612  ABSL_MUST_USE_RESULT Status Polish(TimeLimit* time_limit);
613 
614  // Utility functions to return the current ColIndex of the slack column with
615  // given number. Note that currently, such columns are always present in the
616  // internal representation of a linear program.
617  ColIndex SlackColIndex(RowIndex row) const;
618 
619  // Advances the deterministic time in time_limit with the difference between
620  // the current internal deterministic time and the internal deterministic time
621  // during the last call to this method.
622  // TODO(user): Update the internals of revised simplex so that the time
623  // limit is updated at the source and remove this method.
624  void AdvanceDeterministicTime(TimeLimit* time_limit);
625 
626  // Problem status
627  ProblemStatus problem_status_;
628 
629  // Current number of rows in the problem.
630  RowIndex num_rows_ = RowIndex(0);
631 
632  // Current number of columns in the problem.
633  ColIndex num_cols_ = ColIndex(0);
634 
635  // Index of the first slack variable in the input problem. We assume that all
636  // variables with index greater or equal to first_slack_col_ are slack
637  // variables.
638  ColIndex first_slack_col_ = ColIndex(0);
639 
640  // We're using vectors after profiling and looking at the generated assembly
641  // it's as fast as std::unique_ptr as long as the size is properly reserved
642  // beforehand.
643 
644  // Compact version of the matrix given to Solve().
645  CompactSparseMatrix compact_matrix_;
646 
647  // The transpose of compact_matrix_, it may be empty if it is not needed.
648  CompactSparseMatrix transposed_matrix_;
649 
650  // Stop the algorithm and report feasibility if:
651  // - The primal simplex is used, the problem is primal-feasible and the
652  // current objective value is strictly lower than primal_objective_limit_.
653  // - The dual simplex is used, the problem is dual-feasible and the current
654  // objective value is strictly greater than dual_objective_limit_.
655  Fractional primal_objective_limit_;
656  Fractional dual_objective_limit_;
657 
658  // Current objective (feasibility for Phase-I, user-provided for Phase-II).
659  DenseRow current_objective_;
660 
661  // Array of coefficients for the user-defined objective.
662  // Indexed by column number. Used in Phase-II.
663  DenseRow objective_;
664 
665  // Objective offset and scaling factor of the linear program given to Solve().
666  // This is used to display the correct objective values in the logs with
667  // ComputeInitialProblemObjectiveValue().
668  Fractional objective_offset_;
669  Fractional objective_scaling_factor_;
670 
671  // Used in dual phase I to keep track of the non-basic dual infeasible
672  // columns and their sign of infeasibility (+1 or -1).
673  DenseRow dual_infeasibility_improvement_direction_;
674  int num_dual_infeasible_positions_;
675 
676  // A temporary scattered column that is always reset to all zero after use.
677  ScatteredColumn initially_all_zero_scratchpad_;
678 
679  // Array of column index, giving the column number corresponding
680  // to a given basis row.
681  RowToColMapping basis_;
682  RowToColMapping tmp_basis_;
683 
684  // Vector of strings containing the names of variables.
685  // Indexed by column number.
686  StrictITIVector<ColIndex, std::string> variable_name_;
687 
688  // Only used for logging. What triggered a refactorization.
689  RefactorizationReason last_refactorization_reason_;
690 
691  // Information about the solution computed by the last Solve().
692  Fractional solution_objective_value_;
693  DenseColumn solution_dual_values_;
694  DenseRow solution_reduced_costs_;
695  DenseRow solution_primal_ray_;
696  DenseColumn solution_dual_ray_;
697  DenseRow solution_dual_ray_row_combination_;
698  BasisState solution_state_;
699  bool solution_state_has_been_set_externally_;
700 
701  // If this is cleared, we assume they are none.
702  DenseRow variable_starting_values_;
703 
704  // Flag used by NotifyThatMatrixIsUnchangedForNextSolve() and changing
705  // the behavior of Initialize().
706  bool notify_that_matrix_is_unchanged_ = false;
707 
708  // This is known as 'd' in the literature and is set during each pivot to the
709  // right inverse of the basic entering column of A by ComputeDirection().
710  // ComputeDirection() also fills direction_.non_zeros with the position of the
711  // non-zero.
712  ScatteredColumn direction_;
713  Fractional direction_infinity_norm_;
714 
715  // Used to compute the error 'b - A.x' or 'a - B.d'.
716  DenseColumn error_;
717 
718  // A random number generator. In test we use absl_random_ to have a
719  // non-deterministic behavior and avoid client depending on a golden optimal
720  // solution which prevent us from easily changing the solver.
721  random_engine_t deterministic_random_;
722 #ifndef NDEBUG
723  absl::BitGen absl_random_;
724 #endif
725  absl::BitGenRef random_;
726 
727  // Helpers for logging the solve progress.
728  SolverLogger default_logger_;
729  SolverLogger* logger_ = &default_logger_;
730 
731  // Representation of matrix B using eta matrices and LU decomposition.
732  BasisFactorization basis_factorization_;
733 
734  // Classes responsible for maintaining the data of the corresponding names.
735  VariablesInfo variables_info_;
736  PrimalEdgeNorms primal_edge_norms_;
737  DualEdgeNorms dual_edge_norms_;
738  DynamicMaximum<RowIndex> dual_prices_;
739  VariableValues variable_values_;
740  UpdateRow update_row_;
741  ReducedCosts reduced_costs_;
742  EnteringVariable entering_variable_;
743  PrimalPrices primal_prices_;
744 
745  // Used in dual phase I to hold the price of each possible leaving choices.
746  DenseColumn dual_pricing_vector_;
747  DenseColumn tmp_dual_pricing_vector_;
748 
749  // Temporary memory used by DualMinimize().
750  std::vector<ColIndex> bound_flip_candidates_;
751 
752  // Total number of iterations performed.
753  uint64_t num_iterations_ = 0;
754 
755  // Number of iterations performed during the first (feasibility) phase.
756  uint64_t num_feasibility_iterations_ = 0;
757 
758  // Number of iterations performed during the second (optimization) phase.
759  uint64_t num_optimization_iterations_ = 0;
760 
761  // Number of iterations performed during the push/crossover phase.
762  uint64_t num_push_iterations_ = 0;
763 
764  // Deterministic time for DualPhaseIUpdatePriceOnReducedCostChange().
765  int64_t num_update_price_operations_ = 0;
766 
767  // Total time spent in Solve().
768  double total_time_ = 0.0;
769 
770  // Time spent in the first (feasibility) phase.
771  double feasibility_time_ = 0.0;
772 
773  // Time spent in the second (optimization) phase.
774  double optimization_time_ = 0.0;
775 
776  // Time spent in the push/crossover phase.
777  double push_time_ = 0.0;
778 
779  // The internal deterministic time during the most recent call to
780  // RevisedSimplex::AdvanceDeterministicTime.
781  double last_deterministic_time_update_ = 0.0;
782 
783  // Statistics about the iterations done by PrimalMinimize().
784  IterationStats iteration_stats_;
785 
786  mutable RatioTestStats ratio_test_stats_;
787 
788  // Placeholder for all the function timing stats.
789  // Mutable because we time const functions like ChooseLeavingVariableRow().
790  mutable StatsGroup function_stats_;
791 
792  // Proto holding all the parameters of this algorithm.
793  //
794  // Note that parameters_ may actually change during a solve as the solver may
795  // dynamically adapt some values. It is why we store the argument of the last
796  // SetParameters() call in initial_parameters_ so the next Solve() can reset
797  // it correctly.
798  GlopParameters parameters_;
799  GlopParameters initial_parameters_;
800 
801  // LuFactorization used to test if a pivot will cause the new basis to
802  // not be factorizable.
803  LuFactorization test_lu_;
804 
805  // Number of degenerate iterations made just before the current iteration.
806  int num_consecutive_degenerate_iterations_;
807 
808  // Indicate the current phase of the solve.
809  Phase phase_ = Phase::FEASIBILITY;
810 
811  // Indicates whether simplex ended due to the objective limit being reached.
812  // Note that it's not enough to compare the final objective value with the
813  // limit due to numerical issues (i.e., the limit which is reached within
814  // given tolerance on the internal objective may no longer be reached when the
815  // objective scaling and offset are taken into account).
816  bool objective_limit_reached_;
817 
818  // Temporary SparseColumn used by ChooseLeavingVariableRow().
819  SparseColumn leaving_candidates_;
820 
821  // Temporary vector used to hold the best leaving column candidates that are
822  // tied using the current choosing criteria. We actually only store the tied
823  // candidate #2, #3, ...; because the first tied candidate is remembered
824  // anyway.
825  std::vector<RowIndex> equivalent_leaving_choices_;
826 
827  // This is used by Polish().
828  DenseRow integrality_scale_;
829 
830  DISALLOW_COPY_AND_ASSIGN(RevisedSimplex);
831 };
832 
833 // Hides the details of the dictionary matrix implementation. In the future,
834 // GLOP will support generating the dictionary one row at a time without having
835 // to store the whole matrix in memory.
837  public:
839 
840  // RevisedSimplex cannot be passed const because we have to call a non-const
841  // method ComputeDictionary.
842  // TODO(user): Overload this to take RevisedSimplex* alone when the
843  // caller would normally pass a nullptr for col_scales so this and
844  // ComputeDictionary can take a const& argument.
846  RevisedSimplex* revised_simplex)
847  : dictionary_(
848  ABSL_DIE_IF_NULL(revised_simplex)->ComputeDictionary(col_scales)),
849  basis_vars_(ABSL_DIE_IF_NULL(revised_simplex)->GetBasisVector()) {}
850 
851  ConstIterator begin() const { return dictionary_.begin(); }
852  ConstIterator end() const { return dictionary_.end(); }
853 
854  size_t NumRows() const { return dictionary_.size(); }
855 
856  // TODO(user): This function is a better fit for the future custom iterator.
857  ColIndex GetBasicColumnForRow(RowIndex r) const { return basis_vars_[r]; }
858  SparseRow GetRow(RowIndex r) const { return dictionary_[r]; }
859 
860  private:
861  const RowMajorSparseMatrix dictionary_;
862  const RowToColMapping basis_vars_;
863  DISALLOW_COPY_AND_ASSIGN(RevisedSimplexDictionary);
864 };
865 
866 // TODO(user): When a row-by-row generation of the dictionary is supported,
867 // implement DictionaryIterator class that would call it inside operator*().
868 
869 } // namespace glop
870 } // namespace operations_research
871 
872 #endif // OR_TOOLS_GLOP_REVISED_SIMPLEX_H_
size_type size() const
ParentType::const_iterator const_iterator
Definition: strong_vector.h:90
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
RevisedSimplexDictionary(const DenseRow *col_scales, RevisedSimplex *revised_simplex)
RowMajorSparseMatrix::const_iterator ConstIterator
const GlopParameters & GetParameters() const
const DenseRow & GetDualRayRowCombination() const
Fractional GetVariableValue(ColIndex col) const
void SetIntegralityScale(ColIndex col, Fractional scale)
Fractional GetConstraintActivity(RowIndex row) const
VariableStatus GetVariableStatus(ColIndex col) const
Fractional GetReducedCost(ColIndex col) const
const DenseColumn & GetDualRay() const
ABSL_MUST_USE_RESULT Status Solve(const LinearProgram &lp, TimeLimit *time_limit)
RowMajorSparseMatrix ComputeDictionary(const DenseRow *column_scales)
Fractional GetDualValue(RowIndex row) const
void SetStartingVariableValuesForNextSolve(const DenseRow &values)
ConstraintStatus GetConstraintStatus(RowIndex row) const
void ComputeBasicVariablesForState(const LinearProgram &linear_program, const BasisState &state)
void LoadStateForNextSolve(const BasisState &state)
const BasisFactorization & GetBasisFactorization() const
ColIndex GetBasis(RowIndex row) const
void SetParameters(const GlopParameters &parameters)
const ScatteredRow & GetUnitRowLeftInverse(RowIndex row)
const ScatteredRow & ComputeAndGetUnitRowLeftInverse(RowIndex leaving_row)
Definition: update_row.cc:51
SatParameters parameters
ModelSharedTimeLimit * time_limit
absl::Status status
Definition: g_gurobi.cc:41
ColIndex col
Definition: markowitz.cc:186
RowIndex row
Definition: markowitz.cc:185
StrictITIVector< ColIndex, Fractional > DenseRow
Definition: lp_types.h:341
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Definition: lp_types.h:384
StrictITIVector< RowIndex, Fractional > DenseColumn
Definition: lp_types.h:370
VectorXd ReducedCosts(const PrimalDualHybridGradientParams &params, const ShardedQuadraticProgram &sharded_qp, const VectorXd &primal_solution, const VectorXd &dual_solution, bool use_zero_primal_objective)
Collection of objects used to extend the Constraint Solver library.
std::mt19937_64 random_engine_t
Definition: random_engine.h:23
Fractional target_bound
std::vector< double > lower_bounds
std::vector< double > upper_bounds