OR-Tools  9.6
primal_edge_norms.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 #ifndef OR_TOOLS_GLOP_PRIMAL_EDGE_NORMS_H_
15 #define OR_TOOLS_GLOP_PRIMAL_EDGE_NORMS_H_
16 
17 #include <cstdint>
18 #include <string>
19 #include <vector>
20 
22 #include "ortools/glop/parameters.pb.h"
28 #include "ortools/util/stats.h"
29 
30 namespace operations_research {
31 namespace glop {
32 
33 // This class maintains the primal edge squared norms (and other variants) to be
34 // used in the primal pricing step. Instead of computing the needed values from
35 // scractch at each iteration, it is more efficient to update them incrementally
36 // for each basis pivot applied to the simplex basis matrix B.
37 //
38 // Terminology:
39 // - To each non-basic column 'a' of a matrix A, we can associate an "edge" in
40 // the kernel of A equal to 1.0 on the index of 'a' and '-B^{-1}.a' on the
41 // basic variables.
42 // - 'B^{-1}.a' is called the "right inverse" of 'a'.
43 // - The entering edge is the edge we are following during a simplex step,
44 // and we call "direction" the reverse of this edge restricted to the
45 // basic variables, i.e. the right inverse of the entering column.
46 //
47 // Papers:
48 // - D. Goldfarb, J.K. Reid, "A practicable steepest-edge simplex algorithm"
49 // Mathematical Programming 12 (1977) 361-371, North-Holland.
50 // http://www.springerlink.com/content/g8335137n3j16934/
51 // - J.J. Forrest, D. Goldfarb, "Steepest-edge simplex algorithms for linear
52 // programming", Mathematical Programming 57 (1992) 341-374, North-Holland.
53 // http://www.springerlink.com/content/q645w3t2q229m248/
54 // - Ping-Qi Pan "A fast simplex algorithm for linear programming".
55 // http://www.optimization-online.org/DB_FILE/2007/10/1805.pdf
56 // - Ping-Qi Pan, "Efficient nested pricing in the simplex algorithm",
57 // http://www.optimization-online.org/DB_FILE/2007/10/1810.pdf
59  public:
60  // Takes references to the linear program data we need. Note that we assume
61  // that the matrix will never change in our back, but the other references are
62  // supposed to reflect the correct state.
63  PrimalEdgeNorms(const CompactSparseMatrix& compact_matrix,
64  const VariablesInfo& variables_info,
65  const BasisFactorization& basis_factorization);
66 
67  // Clears, i.e. resets the object to its initial value. This will trigger
68  // a recomputation for the next Get*() method call.
69  void Clear();
70 
71  // If this is true, then the caller must re-factorize the basis before the
72  // next call to GetEdgeSquaredNorms(). This is because the latter will
73  // recompute the norms from scratch and therefore needs a hightened precision
74  // and speed.
75  bool NeedsBasisRefactorization() const;
76 
77  // Depending on the SetPricingRule(), this returns one of the "norms" vector
78  // below. Note that all norms are squared.
79  const DenseRow& GetSquaredNorms();
80 
81  // Returns the primal edge squared norms. This is only valid if the caller
82  // properly called UpdateBeforeBasisPivot() before each basis pivot, or if
83  // this is the first call to this function after a Clear(). Note that only the
84  // relevant columns are filled.
86 
87  // Returns an approximation of the edges norms "devex".
88  // This is only valid if the caller properly called UpdateBeforeBasisPivot()
89  // before each basis pivot, or if this is the first call to this function
90  // after a Clear().
91  const DenseRow& GetDevexWeights();
92 
93  // Returns the L2 norms of all the columns of A.
94  // Note that this is currently not cleared by Clear().
96 
97  // Compares the current entering edge norm with its precise version (using the
98  // direction that wasn't avaible before) and triggers a full recomputation if
99  // the precision is not good enough (see recompute_edges_norm_threshold in
100  // GlopParameters). As a side effect, this replace the entering_col edge
101  // norm with its precise version.
102  //
103  // Returns false if the old norm is less that 0.25 the new one. We might want
104  // to change the leaving variable if this happens.
105  bool TestEnteringEdgeNormPrecision(ColIndex entering_col,
106  const ScatteredColumn& direction);
107 
108  // Updates any internal data BEFORE the given simplex pivot is applied to B.
109  // Note that no updates are needed in case of a bound flip.
110  // The arguments are in order:
111  // - The index of the entering non-basic column of A.
112  // - The index in B of the leaving basic variable.
113  // - The 'direction', i.e. the right inverse of the entering column.
114  // - The update row (see UpdateRow), which will only be computed if needed.
115  void UpdateBeforeBasisPivot(ColIndex entering_col, ColIndex leaving_col,
116  RowIndex leaving_row,
117  const ScatteredColumn& direction,
118  UpdateRow* update_row);
119 
120  // Sets the algorithm parameters.
121  void SetParameters(const GlopParameters& parameters) {
122  parameters_ = parameters;
123  }
124 
125  // This changes what GetSquaredNorms() returns.
126  void SetPricingRule(GlopParameters::PricingRule rule) {
127  pricing_rule_ = rule;
128  }
129 
130  // Registers a boolean that will be set to true each time the norms are or
131  // will be recomputed. This allows anyone that depends on this to know that it
132  // cannot just assume an incremental changes and needs to updates its data.
133  // Important: UpdateBeforeBasisPivot() will not trigger this.
134  void AddRecomputationWatcher(bool* watcher) { watchers_.push_back(watcher); }
135 
136  // Returns a string with statistics about this class.
137  std::string StatString() const { return stats_.StatString(); }
138 
139  // Deterministic time used by the scalar product computation of this class.
140  double DeterministicTime() const {
141  return DeterministicTimeForFpOperations(num_operations_);
142  }
143 
144  private:
145  // Statistics about this class.
146  struct Stats : public StatsGroup {
147  Stats()
148  : StatsGroup("PrimalEdgeNorms"),
149  direction_left_inverse_density("direction_left_inverse_density",
150  this),
151  direction_left_inverse_accuracy("direction_left_inverse_accuracy",
152  this),
153  edges_norm_accuracy("edges_norm_accuracy", this),
154  lower_bounded_norms("lower_bounded_norms", this) {}
155  RatioDistribution direction_left_inverse_density;
156  DoubleDistribution direction_left_inverse_accuracy;
157  DoubleDistribution edges_norm_accuracy;
158  IntegerDistribution lower_bounded_norms;
159  };
160 
161  // Recompute the matrix column L2 norms from scratch.
162  void ComputeMatrixColumnNorms();
163 
164  // Recompute the edge squared L2 norms from scratch.
165  void ComputeEdgeSquaredNorms();
166 
167  // Compute the left inverse of the direction.
168  // The first argument is there for checking precision.
169  void ComputeDirectionLeftInverse(ColIndex entering_col,
170  const ScatteredColumn& direction);
171 
172  // Updates edges_squared_norm_ according to the given pivot.
173  void UpdateEdgeSquaredNorms(ColIndex entering_col, ColIndex leaving_col,
174  RowIndex leaving_row,
175  const DenseColumn& direction,
176  const UpdateRow& update_row);
177 
178  // Resets all devex weights to 1.0 .
179  void ResetDevexWeights();
180 
181  // Updates devex_weights_ according to the given pivot.
182  void UpdateDevexWeights(ColIndex entering_col, ColIndex leaving_col,
183  RowIndex leaving_row, const DenseColumn& direction,
184  const UpdateRow& update_row);
185 
186  // Problem data that should be updated from outside.
187  const CompactSparseMatrix& compact_matrix_;
188  const VariablesInfo& variables_info_;
189  const BasisFactorization& basis_factorization_;
190 
191  // Internal data.
192  GlopParameters parameters_;
193  GlopParameters::PricingRule pricing_rule_ = GlopParameters::DANTZIG;
194  Stats stats_;
195 
196  // Booleans to control what happens on the next ChooseEnteringColumn() call.
197  bool must_refactorize_basis_;
198  bool recompute_edge_squared_norms_;
199  bool reset_devex_weights_;
200 
201  // Norm^2 of the edges of the relevant columns of A.
202  DenseRow edge_squared_norms_;
203 
204  // Norm of all the columns of A.
205  DenseRow matrix_column_norms_;
206 
207  // Approximation of edges norms "devex".
208  // Denoted by vector 'w' in Pin Qi Pan (1810.pdf section 1.1.4)
209  // At any time, devex_weights_ >= 1.0.
210  DenseRow devex_weights_;
211 
212  // Tracks number of updates of the devex weights since we have to reset
213  // them to 1.0 every now and then.
214  int num_devex_updates_since_reset_;
215 
216  // Left inverse by B of the 'direction'. This is the transpose of 'v' in the
217  // steepest edge paper. Its scalar product with a column 'a' of A gives the
218  // value of the scalar product of the 'direction' with the right inverse of
219  // 'a'.
220  ScatteredRow direction_left_inverse_;
221 
222  // Used by DeterministicTime().
223  int64_t num_operations_;
224 
225  // Boolean(s) to set to false when the norms are changed outside of the
226  // UpdateBeforeBasisPivot() function.
227  std::vector<bool*> watchers_;
228 
229  DISALLOW_COPY_AND_ASSIGN(PrimalEdgeNorms);
230 };
231 
232 } // namespace glop
233 } // namespace operations_research
234 
235 #endif // OR_TOOLS_GLOP_PRIMAL_EDGE_NORMS_H_
PrimalEdgeNorms(const CompactSparseMatrix &compact_matrix, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization)
bool TestEnteringEdgeNormPrecision(ColIndex entering_col, const ScatteredColumn &direction)
void UpdateBeforeBasisPivot(ColIndex entering_col, ColIndex leaving_col, RowIndex leaving_row, const ScatteredColumn &direction, UpdateRow *update_row)
void SetPricingRule(GlopParameters::PricingRule rule)
void SetParameters(const GlopParameters &parameters)
SatParameters parameters
StrictITIVector< ColIndex, Fractional > DenseRow
Definition: lp_types.h:341
StrictITIVector< RowIndex, Fractional > DenseColumn
Definition: lp_types.h:370
static double DeterministicTimeForFpOperations(int64_t n)
Definition: lp_types.h:421
Collection of objects used to extend the Constraint Solver library.