OR-Tools  9.0
variable_values.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 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 
15 
18 
19 namespace operations_research {
20 namespace glop {
21 
23  const CompactSparseMatrix& matrix,
24  const RowToColMapping& basis,
25  const VariablesInfo& variables_info,
26  const BasisFactorization& basis_factorization,
27  DualEdgeNorms* dual_edge_norms,
28  DynamicMaximum<RowIndex>* dual_prices)
29  : parameters_(parameters),
30  matrix_(matrix),
31  basis_(basis),
32  variables_info_(variables_info),
33  basis_factorization_(basis_factorization),
34  dual_edge_norms_(dual_edge_norms),
35  dual_prices_(dual_prices),
36  stats_("VariableValues") {}
37 
39  SCOPED_TIME_STAT(&stats_);
40  const DenseRow& lower_bounds = variables_info_.GetVariableLowerBounds();
41  const DenseRow& upper_bounds = variables_info_.GetVariableUpperBounds();
42  variable_values_.resize(matrix_.num_cols(), 0.0);
43  switch (variables_info_.GetStatusRow()[col]) {
47  variable_values_[col] = lower_bounds[col];
48  break;
51  variable_values_[col] = lower_bounds[col];
52  break;
55  variable_values_[col] = upper_bounds[col];
56  break;
60  variable_values_[col] = 0.0;
61  break;
63  LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't "
64  << "be called on a BASIC variable.";
65  break;
66  }
67  // Note that there is no default value in the switch() statement above to
68  // get a compile-time error if a value is missing.
69 }
70 
72  const DenseRow& lower_bounds = variables_info_.GetVariableLowerBounds();
73  const DenseRow& upper_bounds = variables_info_.GetVariableUpperBounds();
74  const VariableStatusRow& statuses = variables_info_.GetStatusRow();
75  const ColIndex num_cols = matrix_.num_cols();
76  variable_values_.resize(num_cols, 0.0);
77  for (ColIndex col(0); col < num_cols; ++col) {
78  switch (statuses[col]) {
80  ABSL_FALLTHROUGH_INTENDED;
82  variable_values_[col] = lower_bounds[col];
83  break;
85  variable_values_[col] = upper_bounds[col];
86  break;
88  variable_values_[col] = 0.0;
89  break;
91  break;
92  }
93  }
94 }
95 
97  SCOPED_TIME_STAT(&stats_);
98  DCHECK(basis_factorization_.IsRefactorized());
99  const RowIndex num_rows = matrix_.num_rows();
100  scratchpad_.non_zeros.clear();
101  scratchpad_.values.AssignToZero(num_rows);
102  for (const ColIndex col : variables_info_.GetNotBasicBitRow()) {
103  const Fractional value = variable_values_[col];
104  matrix_.ColumnAddMultipleToDenseColumn(col, -value, &scratchpad_.values);
105  }
106  basis_factorization_.RightSolve(&scratchpad_);
107  for (RowIndex row(0); row < num_rows; ++row) {
108  variable_values_[basis_[row]] = scratchpad_[row];
109  }
110 
111  // This makes sure that they will be recomputed if needed.
112  dual_prices_->Clear();
113 }
114 
116  SCOPED_TIME_STAT(&stats_);
117  scratchpad_.non_zeros.clear();
118  scratchpad_.values.AssignToZero(matrix_.num_rows());
119  const ColIndex num_cols = matrix_.num_cols();
120  for (ColIndex col(0); col < num_cols; ++col) {
121  const Fractional value = variable_values_[col];
122  matrix_.ColumnAddMultipleToDenseColumn(col, value, &scratchpad_.values);
123  }
124  return InfinityNorm(scratchpad_.values);
125 }
126 
128  SCOPED_TIME_STAT(&stats_);
129  Fractional primal_infeasibility = 0.0;
130  const ColIndex num_cols = matrix_.num_cols();
131  for (ColIndex col(0); col < num_cols; ++col) {
132  const Fractional col_infeasibility = std::max(
133  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
134  primal_infeasibility = std::max(primal_infeasibility, col_infeasibility);
135  }
136  return primal_infeasibility;
137 }
138 
140  SCOPED_TIME_STAT(&stats_);
141  Fractional sum = 0.0;
142  const ColIndex num_cols = matrix_.num_cols();
143  for (ColIndex col(0); col < num_cols; ++col) {
144  const Fractional col_infeasibility = std::max(
145  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
146  sum += std::max(0.0, col_infeasibility);
147  }
148  return sum;
149 }
150 
152  ColIndex entering_col, Fractional step) {
153  SCOPED_TIME_STAT(&stats_);
154  DCHECK(IsFinite(step));
155 
156  // Note(user): Some positions are ignored during the primal ratio test:
157  // - The rows for which direction_[row] < tolerance.
158  // - The non-zeros of direction_ignored_position_ in case of degeneracy.
159  // Such positions may result in basic variables going out of their bounds by
160  // more than the allowed tolerance. We could choose not to update these
161  // variables or not make them take out-of-bound values, but this would
162  // introduce artificial errors.
163 
164  // Note that there is no need to call variables_info_.Update() on basic
165  // variables when they change values. Note also that the status of
166  // entering_col will be updated later.
167  for (const auto e : direction) {
168  const ColIndex col = basis_[e.row()];
169  variable_values_[col] -= e.coefficient() * step;
170  }
171  variable_values_[entering_col] += step;
172 }
173 
175  const std::vector<ColIndex>& cols_to_update, bool update_basic_variables) {
176  SCOPED_TIME_STAT(&stats_);
177  if (!update_basic_variables) {
178  for (ColIndex col : cols_to_update) {
180  }
181  return;
182  }
183 
184  const RowIndex num_rows = matrix_.num_rows();
185  initially_all_zero_scratchpad_.values.resize(num_rows, 0.0);
186  DCHECK(IsAllZero(initially_all_zero_scratchpad_.values));
187  initially_all_zero_scratchpad_.ClearSparseMask();
188  bool use_dense = false;
189  for (ColIndex col : cols_to_update) {
190  const Fractional old_value = variable_values_[col];
192  if (use_dense) {
194  col, variable_values_[col] - old_value,
195  &initially_all_zero_scratchpad_.values);
196  } else {
198  col, variable_values_[col] - old_value,
199  &initially_all_zero_scratchpad_);
200  use_dense = initially_all_zero_scratchpad_.ShouldUseDenseIteration();
201  }
202  }
203  initially_all_zero_scratchpad_.ClearSparseMask();
204  initially_all_zero_scratchpad_.ClearNonZerosIfTooDense();
205 
206  basis_factorization_.RightSolve(&initially_all_zero_scratchpad_);
207  if (initially_all_zero_scratchpad_.non_zeros.empty()) {
208  for (RowIndex row(0); row < num_rows; ++row) {
209  variable_values_[basis_[row]] -= initially_all_zero_scratchpad_[row];
210  }
211  initially_all_zero_scratchpad_.values.AssignToZero(num_rows);
213  return;
214  }
215 
216  for (const auto e : initially_all_zero_scratchpad_) {
217  variable_values_[basis_[e.row()]] -= e.coefficient();
218  initially_all_zero_scratchpad_[e.row()] = 0.0;
219  }
220  UpdateDualPrices(initially_all_zero_scratchpad_.non_zeros);
221  initially_all_zero_scratchpad_.non_zeros.clear();
222 }
223 
225  SCOPED_TIME_STAT(&stats_);
226  const RowIndex num_rows = matrix_.num_rows();
227  dual_prices_->ClearAndResize(num_rows);
228  dual_prices_->StartDenseUpdates();
229 
230  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
231  const DenseColumn& squared_norms = dual_edge_norms_->GetEdgeSquaredNorms();
232  for (RowIndex row(0); row < num_rows; ++row) {
233  const ColIndex col = basis_[row];
234  const Fractional infeasibility = std::max(GetUpperBoundInfeasibility(col),
235  GetLowerBoundInfeasibility(col));
236  if (infeasibility > tolerance) {
237  dual_prices_->DenseAddOrUpdate(
238  row, Square(infeasibility) / squared_norms[row]);
239  }
240  }
241 }
242 
243 void VariableValues::UpdateDualPrices(const std::vector<RowIndex>& rows) {
244  if (dual_prices_->Size() != matrix_.num_rows()) {
246  return;
247  }
248 
249  // Note(user): this is the same as the code in
250  // RecomputePrimalInfeasibilityInformation(), but we do need the clear part.
251  SCOPED_TIME_STAT(&stats_);
252  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
253  const DenseColumn& squared_norms = dual_edge_norms_->GetEdgeSquaredNorms();
254  for (const RowIndex row : rows) {
255  const ColIndex col = basis_[row];
256  const Fractional infeasibility = std::max(GetUpperBoundInfeasibility(col),
257  GetLowerBoundInfeasibility(col));
258  if (infeasibility > tolerance) {
259  dual_prices_->AddOrUpdate(row,
260  Square(infeasibility) / squared_norms[row]);
261  } else {
262  dual_prices_->Remove(row);
263  }
264  }
265 }
266 
267 } // namespace glop
268 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:894
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
void ColumnAddMultipleToSparseScatteredColumn(ColIndex col, Fractional multiplier, ScatteredColumn *column) const
Definition: sparse.h:405
void ColumnAddMultipleToDenseColumn(ColIndex col, Fractional multiplier, DenseColumn *dense_column) const
Definition: sparse.h:393
void AddOrUpdate(Index position, Fractional value)
Definition: pricing.h:185
void DenseAddOrUpdate(Index position, Fractional value)
Definition: pricing.h:176
void UpdateGivenNonBasicVariables(const std::vector< ColIndex > &cols_to_update, bool update_basic_variables)
void UpdateDualPrices(const std::vector< RowIndex > &row)
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 DenseRow & GetVariableUpperBounds() const
const DenseRow & GetVariableLowerBounds() const
const DenseBitRow & GetNotBasicBitRow() const
const VariableStatusRow & GetStatusRow() const
SatParameters parameters
int64_t value
ColIndex col
Definition: markowitz.cc:183
RowIndex row
Definition: markowitz.cc:182
Fractional Square(Fractional f)
Fractional InfinityNorm(const DenseColumn &v)
bool IsAllZero(const Container &input)
bool IsFinite(Fractional value)
Definition: lp_types.h:91
const double kInfinity
Definition: lp_types.h:84
Collection of objects used to extend the Constraint Solver library.
std::vector< double > lower_bounds
std::vector< double > upper_bounds
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:438
bool ShouldUseDenseIteration(double ratio_for_using_dense_representation) const
void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation)
StrictITIVector< Index, Fractional > values