OR-Tools  9.2
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;
58  LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't "
59  << "be called on a FREE variable.";
60  break;
62  LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't "
63  << "be called on a BASIC variable.";
64  break;
65  }
66  // Note that there is no default value in the switch() statement above to
67  // get a compile-time error if a value is missing.
68 }
69 
71  const DenseRow& free_initial_value) {
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] =
89  col < free_initial_value.size() ? free_initial_value[col] : 0.0;
90  break;
92  break;
93  }
94  }
95 }
96 
98  SCOPED_TIME_STAT(&stats_);
99  DCHECK(basis_factorization_.IsRefactorized());
100  const RowIndex num_rows = matrix_.num_rows();
101  scratchpad_.non_zeros.clear();
102  scratchpad_.values.AssignToZero(num_rows);
103  for (const ColIndex col : variables_info_.GetNotBasicBitRow()) {
104  const Fractional value = variable_values_[col];
105  matrix_.ColumnAddMultipleToDenseColumn(col, -value, &scratchpad_.values);
106  }
107  basis_factorization_.RightSolve(&scratchpad_);
108  for (RowIndex row(0); row < num_rows; ++row) {
109  variable_values_[basis_[row]] = scratchpad_[row];
110  }
111 
112  // This makes sure that they will be recomputed if needed.
113  dual_prices_->Clear();
114 }
115 
117  SCOPED_TIME_STAT(&stats_);
118  scratchpad_.non_zeros.clear();
119  scratchpad_.values.AssignToZero(matrix_.num_rows());
120  const ColIndex num_cols = matrix_.num_cols();
121  for (ColIndex col(0); col < num_cols; ++col) {
122  const Fractional value = variable_values_[col];
123  matrix_.ColumnAddMultipleToDenseColumn(col, value, &scratchpad_.values);
124  }
125  return InfinityNorm(scratchpad_.values);
126 }
127 
129  SCOPED_TIME_STAT(&stats_);
130  Fractional primal_infeasibility = 0.0;
131  const ColIndex num_cols = matrix_.num_cols();
132  for (ColIndex col(0); col < num_cols; ++col) {
133  const Fractional col_infeasibility = std::max(
134  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
135  primal_infeasibility = std::max(primal_infeasibility, col_infeasibility);
136  }
137  return primal_infeasibility;
138 }
139 
141  SCOPED_TIME_STAT(&stats_);
142  Fractional sum = 0.0;
143  const ColIndex num_cols = matrix_.num_cols();
144  for (ColIndex col(0); col < num_cols; ++col) {
145  const Fractional col_infeasibility = std::max(
146  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
147  sum += std::max(0.0, col_infeasibility);
148  }
149  return sum;
150 }
151 
153  ColIndex entering_col, Fractional step) {
154  SCOPED_TIME_STAT(&stats_);
155  DCHECK(IsFinite(step));
156 
157  // Note(user): Some positions are ignored during the primal ratio test:
158  // - The rows for which direction_[row] < tolerance.
159  // - The non-zeros of direction_ignored_position_ in case of degeneracy.
160  // Such positions may result in basic variables going out of their bounds by
161  // more than the allowed tolerance. We could choose not to update these
162  // variables or not make them take out-of-bound values, but this would
163  // introduce artificial errors.
164 
165  // Note that there is no need to call variables_info_.Update() on basic
166  // variables when they change values. Note also that the status of
167  // entering_col will be updated later.
168  for (const auto e : direction) {
169  const ColIndex col = basis_[e.row()];
170  variable_values_[col] -= e.coefficient() * step;
171  }
172  variable_values_[entering_col] += step;
173 }
174 
176  const std::vector<ColIndex>& cols_to_update, bool update_basic_variables) {
177  SCOPED_TIME_STAT(&stats_);
178  if (!update_basic_variables) {
179  for (ColIndex col : cols_to_update) {
181  }
182  return;
183  }
184 
185  const RowIndex num_rows = matrix_.num_rows();
186  initially_all_zero_scratchpad_.values.resize(num_rows, 0.0);
187  DCHECK(IsAllZero(initially_all_zero_scratchpad_.values));
188  initially_all_zero_scratchpad_.ClearSparseMask();
189  bool use_dense = false;
190  for (ColIndex col : cols_to_update) {
191  const Fractional old_value = variable_values_[col];
193  if (use_dense) {
195  col, variable_values_[col] - old_value,
196  &initially_all_zero_scratchpad_.values);
197  } else {
199  col, variable_values_[col] - old_value,
200  &initially_all_zero_scratchpad_);
201  use_dense = initially_all_zero_scratchpad_.ShouldUseDenseIteration();
202  }
203  }
204  initially_all_zero_scratchpad_.ClearSparseMask();
205  initially_all_zero_scratchpad_.ClearNonZerosIfTooDense();
206 
207  basis_factorization_.RightSolve(&initially_all_zero_scratchpad_);
208  if (initially_all_zero_scratchpad_.non_zeros.empty()) {
209  for (RowIndex row(0); row < num_rows; ++row) {
210  variable_values_[basis_[row]] -= initially_all_zero_scratchpad_[row];
211  }
212  initially_all_zero_scratchpad_.values.AssignToZero(num_rows);
214  return;
215  }
216 
217  for (const auto e : initially_all_zero_scratchpad_) {
218  variable_values_[basis_[e.row()]] -= e.coefficient();
219  initially_all_zero_scratchpad_[e.row()] = 0.0;
220  }
221  UpdateDualPrices(initially_all_zero_scratchpad_.non_zeros);
222  initially_all_zero_scratchpad_.non_zeros.clear();
223 }
224 
226  SCOPED_TIME_STAT(&stats_);
227  const RowIndex num_rows = matrix_.num_rows();
228  dual_prices_->ClearAndResize(num_rows);
229  dual_prices_->StartDenseUpdates();
230 
231  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
232  const DenseColumn& squared_norms = dual_edge_norms_->GetEdgeSquaredNorms();
233  for (RowIndex row(0); row < num_rows; ++row) {
234  const ColIndex col = basis_[row];
235  const Fractional infeasibility = std::max(GetUpperBoundInfeasibility(col),
236  GetLowerBoundInfeasibility(col));
237  if (infeasibility > tolerance) {
238  dual_prices_->DenseAddOrUpdate(
239  row, Square(infeasibility) / squared_norms[row]);
240  }
241  }
242 }
243 
244 void VariableValues::UpdateDualPrices(const std::vector<RowIndex>& rows) {
245  if (dual_prices_->Size() != matrix_.num_rows()) {
247  return;
248  }
249 
250  // Note(user): this is the same as the code in
251  // RecomputePrimalInfeasibilityInformation(), but we do need the clear part.
252  SCOPED_TIME_STAT(&stats_);
253  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
254  const DenseColumn& squared_norms = dual_edge_norms_->GetEdgeSquaredNorms();
255  for (const RowIndex row : rows) {
256  const ColIndex col = basis_[row];
257  const Fractional infeasibility = std::max(GetUpperBoundInfeasibility(col),
258  GetLowerBoundInfeasibility(col));
259  if (infeasibility > tolerance) {
260  dual_prices_->AddOrUpdate(row,
261  Square(infeasibility) / squared_norms[row]);
262  } else {
263  dual_prices_->Remove(row);
264  }
265  }
266 }
267 
268 } // namespace glop
269 } // namespace operations_research
Fractional InfinityNorm(const DenseColumn &v)
void UpdateDualPrices(const std::vector< RowIndex > &row)
const DenseBitRow & GetNotBasicBitRow() const
std::vector< double > lower_bounds
bool ShouldUseDenseIteration(double ratio_for_using_dense_representation) const
#define LOG(severity)
Definition: base/logging.h:420
ColIndex col
Definition: markowitz.cc:183
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:438
RowIndex row
Definition: markowitz.cc:182
bool IsFinite(Fractional value)
Definition: lp_types.h:91
void UpdateGivenNonBasicVariables(const std::vector< ColIndex > &cols_to_update, bool update_basic_variables)
int64_t max
Definition: alldiff_cst.cc:140
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:891
StrictITIVector< Index, Fractional > values
bool IsAllZero(const Container &input)
void ColumnAddMultipleToSparseScatteredColumn(ColIndex col, Fractional multiplier, ScatteredColumn *column) const
Definition: sparse.h:410
void AddOrUpdate(Index position, Fractional value)
Definition: pricing.h:185
const double kInfinity
Definition: lp_types.h:84
const DenseRow & GetVariableUpperBounds() const
const DenseRow & GetVariableLowerBounds() const
void DenseAddOrUpdate(Index position, Fractional value)
Definition: pricing.h:176
#define DCHECK(condition)
Definition: base/logging.h:889
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:890
void UpdateOnPivoting(const ScatteredColumn &direction, ColIndex entering_col, Fractional step)
Fractional Square(Fractional f)
Collection of objects used to extend the Constraint Solver library.
const VariableStatusRow & GetStatusRow() const
SatParameters parameters
std::vector< double > upper_bounds
void ResetAllNonBasicVariableValues(const DenseRow &free_initial_values)
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)
void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation)
void ColumnAddMultipleToDenseColumn(ColIndex col, Fractional multiplier, DenseColumn *dense_column) const
Definition: sparse.h:398
int64_t value