OR-Tools  9.6
variable_values.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_VARIABLE_VALUES_H_
15 #define OR_TOOLS_GLOP_VARIABLE_VALUES_H_
16 
17 #include <string>
18 #include <vector>
19 
22 #include "ortools/glop/pricing.h"
26 #include "ortools/util/stats.h"
27 
28 namespace operations_research {
29 namespace glop {
30 
31 // Class holding all the variable values and responsible for updating them. The
32 // variable values 'x' are such that 'A.x = 0' where A is the linear program
33 // matrix. This is because slack variables with bounds corresponding to the
34 // constraints bounds were added to the linear program matrix A.
35 //
36 // Some remarks:
37 // - For convenience, the variable values are stored in a DenseRow and indexed
38 // by ColIndex, like the variables and the columns of A.
39 // - During the dual-simplex, all non-basic variable values are at their exact
40 // bounds or exactly at 0.0 for a free variable.
41 // - During the primal-simplex, the non-basic variable values may not be exactly
42 // at their bounds because of bound-shifting during degenerate simplex
43 // pivoting which is implemented by not setting the variable values exactly at
44 // their bounds to have a lower primal residual error.
46  public:
47  VariableValues(const GlopParameters& parameters,
48  const CompactSparseMatrix& matrix,
49  const RowToColMapping& basis,
50  const VariablesInfo& variables_info,
51  const BasisFactorization& basis_factorization,
52  DualEdgeNorms* dual_edge_norms,
53  DynamicMaximum<RowIndex>* dual_prices);
54 
55  // Getters for the variable values.
56  const Fractional Get(ColIndex col) const { return variable_values_[col]; }
57  const DenseRow& GetDenseRow() const { return variable_values_; }
58 
59  // Sets the value of a non-basic variable to the exact value implied by its
60  // current status. Note that the basic variable values are NOT updated by this
61  // function and it is up to the client to call RecomputeBasicVariableValues().
63 
64  // Calls SetNonBasicVariableValueFromStatus() on all non-basic variables. We
65  // accept any size for free_initial_values, for columns col that are valid
66  // indices, free_initial_values[col] will be used instead of 0.0 for a free
67  // column. If free_initial_values is empty, then we have the default behavior
68  // of starting at zero for all FREE variables.
69  //
70  // Note(user): It is okay to always use the same value to reset a FREE
71  // variable because as soon as a FREE variable value is modified, this
72  // variable shouldn't be FREE anymore. It will either move to a bound or enter
73  // the basis, these are the only options.
74  void ResetAllNonBasicVariableValues(const DenseRow& free_initial_values);
75 
76  // Recomputes the value of the basic variables from the non-basic ones knowing
77  // that the linear program matrix A times the variable values vector must be
78  // zero. It is better to call this when the basis is refactorized. This
79  // is checked in debug mode.
81 
82  // Computes the infinity norm of A.x where A is the linear_program matrix and
83  // x is the variable values column.
85 
86  // Computes the maximum bound error for all the variables, defined as the
87  // distance of the current value of the variable to its interval
88  // [lower bound, upper bound]. The infeasibility is thus equal to 0.0 if the
89  // current value falls within the bounds, to the distance to lower_bound
90  // (resp. upper_bound), if the current value is below (resp. above)
91  // lower_bound (resp. upper_bound).
94 
95  // Updates the variable during a simplex pivot:
96  // - step * direction is substracted from the basic variables value.
97  // - step is added to the entering column value.
98  void UpdateOnPivoting(const ScatteredColumn& direction, ColIndex entering_col,
99  Fractional step);
100 
101  // Batch version of SetNonBasicVariableValueFromStatus(). This function also
102  // updates the basic variable values and infeasibility statuses if
103  // update_basic_variables is true. The update is done in an incremental way
104  // and is thus more efficient than calling afterwards
105  // RecomputeBasicVariableValues() and RecomputeDualPrices().
106  void UpdateGivenNonBasicVariables(const std::vector<ColIndex>& cols_to_update,
107  bool update_basic_variables);
108 
109  // Functions dealing with the primal-infeasible basic variables. A basic
110  // variable is primal-infeasible if its infeasibility is stricly greater than
111  // the primal feasibility tolerance. These are exactly the dual "prices" once
112  // recalled by the norms. This is only used during the dual simplex.
113  //
114  // This information is only available after a call to RecomputeDualPrices()
115  // and has to be kept in sync by calling UpdateDualPrices() for the rows that
116  // changed values.
117  //
118  // TODO(user): On some problem like stp3d.mps or pds-100.mps, using different
119  // price like abs(infeasibility) / squared_norms give better result. Some
120  // solver switch according to a criteria like all entry are +1/-1, the column
121  // have no more than 24 non-zero and the average column size is no more than
122  // 6! Understand and implement some variant of this? I think the gain is
123  // mainly because of using sparser vectors?
124  void RecomputeDualPrices(bool put_more_importance_on_norm = false);
125  void UpdateDualPrices(absl::Span<const RowIndex> row);
126 
127  // The primal phase I objective is related to the primal infeasible
128  // information above. The cost of a basic column will be 1 if the variable is
129  // above its upper bound by strictly more than the primal tolerance, and -1 if
130  // it is lower than its lower bound by strictly less than the same tolerance.
131  //
132  // Returns true iff some cost changed.
133  template <typename Rows>
134  bool UpdatePrimalPhaseICosts(const Rows& rows, DenseRow* objective);
135 
136  // Sets the variable value of a given column.
137  void Set(ColIndex col, Fractional value) { variable_values_[col] = value; }
138 
139  // Parameters and stats functions.
140  std::string StatString() const { return stats_.StatString(); }
141 
142  private:
143  // It is important that the infeasibility is always computed in the same
144  // way. So the code should always use these functions that returns a positive
145  // value when the variable is out of bounds.
146  Fractional GetUpperBoundInfeasibility(ColIndex col) const {
147  return variable_values_[col] -
148  variables_info_.GetVariableUpperBounds()[col];
149  }
150  Fractional GetLowerBoundInfeasibility(ColIndex col) const {
151  return variables_info_.GetVariableLowerBounds()[col] -
152  variable_values_[col];
153  }
154 
155  // Input problem data.
156  const GlopParameters& parameters_;
157  const CompactSparseMatrix& matrix_;
158  const RowToColMapping& basis_;
159  const VariablesInfo& variables_info_;
160  const BasisFactorization& basis_factorization_;
161 
162  // This is set by RecomputeDualPrices() so that UpdateDualPrices() use
163  // the same formula.
164  bool put_more_importance_on_norm_ = false;
165 
166  // The dual prices are a normalized version of the primal infeasibility.
167  DualEdgeNorms* dual_edge_norms_;
168  DynamicMaximum<RowIndex>* dual_prices_;
169 
170  // Values of the variables.
171  DenseRow variable_values_;
172 
173  mutable StatsGroup stats_;
174  mutable ScatteredColumn scratchpad_;
175 
176  // A temporary scattered column that is always reset to all zero after use.
177  ScatteredColumn initially_all_zero_scratchpad_;
178 
179  DISALLOW_COPY_AND_ASSIGN(VariableValues);
180 };
181 
182 template <typename Rows>
184  DenseRow* objective) {
185  SCOPED_TIME_STAT(&stats_);
186  bool changed = false;
187  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
188  for (const RowIndex row : rows) {
189  const ColIndex col = basis_[row];
190  Fractional new_cost = 0.0;
191  if (GetUpperBoundInfeasibility(col) > tolerance) {
192  new_cost = 1.0;
193  } else if (GetLowerBoundInfeasibility(col) > tolerance) {
194  new_cost = -1.0;
195  }
196  if (new_cost != (*objective)[col]) {
197  changed = true;
198  (*objective)[col] = new_cost;
199  }
200  }
201  return changed;
202 }
203 
204 } // namespace glop
205 } // namespace operations_research
206 
207 #endif // OR_TOOLS_GLOP_VARIABLE_VALUES_H_
std::string StatString() const
Definition: stats.cc:77
void UpdateDualPrices(absl::Span< const RowIndex > row)
void Set(ColIndex col, Fractional value)
void UpdateGivenNonBasicVariables(const std::vector< ColIndex > &cols_to_update, bool update_basic_variables)
void ResetAllNonBasicVariableValues(const DenseRow &free_initial_values)
void RecomputeDualPrices(bool put_more_importance_on_norm=false)
void UpdateOnPivoting(const ScatteredColumn &direction, ColIndex entering_col, Fractional step)
VariableValues(const GlopParameters &parameters, const CompactSparseMatrix &matrix, const RowToColMapping &basis, const VariablesInfo &variables_info, const BasisFactorization &basis_factorization, DualEdgeNorms *dual_edge_norms, DynamicMaximum< RowIndex > *dual_prices)
const Fractional Get(ColIndex col) const
bool UpdatePrimalPhaseICosts(const Rows &rows, DenseRow *objective)
const DenseRow & GetVariableUpperBounds() const
const DenseRow & GetVariableLowerBounds() const
SatParameters parameters
int64_t value
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
Collection of objects used to extend the Constraint Solver library.
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:439