OR-Tools  9.6
variable_values.cc
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 
15 
16 #include <algorithm>
17 #include <vector>
18 
21 
22 namespace operations_research {
23 namespace glop {
24 
26  const CompactSparseMatrix& matrix,
27  const RowToColMapping& basis,
28  const VariablesInfo& variables_info,
29  const BasisFactorization& basis_factorization,
30  DualEdgeNorms* dual_edge_norms,
31  DynamicMaximum<RowIndex>* dual_prices)
32  : parameters_(parameters),
33  matrix_(matrix),
34  basis_(basis),
35  variables_info_(variables_info),
36  basis_factorization_(basis_factorization),
37  dual_edge_norms_(dual_edge_norms),
38  dual_prices_(dual_prices),
39  stats_("VariableValues") {}
40 
42  SCOPED_TIME_STAT(&stats_);
43  const DenseRow& lower_bounds = variables_info_.GetVariableLowerBounds();
44  const DenseRow& upper_bounds = variables_info_.GetVariableUpperBounds();
45  variable_values_.resize(matrix_.num_cols(), 0.0);
46  switch (variables_info_.GetStatusRow()[col]) {
48  DCHECK_NE(-kInfinity, lower_bounds[col]);
49  DCHECK_EQ(lower_bounds[col], upper_bounds[col]);
50  variable_values_[col] = lower_bounds[col];
51  break;
53  DCHECK_NE(-kInfinity, lower_bounds[col]);
54  variable_values_[col] = lower_bounds[col];
55  break;
57  DCHECK_NE(kInfinity, upper_bounds[col]);
58  variable_values_[col] = upper_bounds[col];
59  break;
61  LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't "
62  << "be called on a FREE variable.";
63  break;
65  LOG(DFATAL) << "SetNonBasicVariableValueFromStatus() shouldn't "
66  << "be called on a BASIC variable.";
67  break;
68  }
69  // Note that there is no default value in the switch() statement above to
70  // get a compile-time error if a value is missing.
71 }
72 
74  const DenseRow& free_initial_value) {
75  const DenseRow& lower_bounds = variables_info_.GetVariableLowerBounds();
76  const DenseRow& upper_bounds = variables_info_.GetVariableUpperBounds();
77  const VariableStatusRow& statuses = variables_info_.GetStatusRow();
78  const ColIndex num_cols = matrix_.num_cols();
79  variable_values_.resize(num_cols, 0.0);
80  for (ColIndex col(0); col < num_cols; ++col) {
81  switch (statuses[col]) {
83  ABSL_FALLTHROUGH_INTENDED;
85  variable_values_[col] = lower_bounds[col];
86  break;
88  variable_values_[col] = upper_bounds[col];
89  break;
91  variable_values_[col] =
92  col < free_initial_value.size() ? free_initial_value[col] : 0.0;
93  break;
95  break;
96  }
97  }
98 }
99 
101  SCOPED_TIME_STAT(&stats_);
102  DCHECK(basis_factorization_.IsRefactorized());
103  const RowIndex num_rows = matrix_.num_rows();
104  scratchpad_.non_zeros.clear();
105  scratchpad_.values.AssignToZero(num_rows);
106  for (const ColIndex col : variables_info_.GetNotBasicBitRow()) {
107  const Fractional value = variable_values_[col];
108  matrix_.ColumnAddMultipleToDenseColumn(col, -value, &scratchpad_.values);
109  }
110  basis_factorization_.RightSolve(&scratchpad_);
111  for (RowIndex row(0); row < num_rows; ++row) {
112  variable_values_[basis_[row]] = scratchpad_[row];
113  }
114 
115  // This makes sure that they will be recomputed if needed.
116  dual_prices_->Clear();
117 }
118 
120  SCOPED_TIME_STAT(&stats_);
121  scratchpad_.non_zeros.clear();
122  scratchpad_.values.AssignToZero(matrix_.num_rows());
123  const ColIndex num_cols = matrix_.num_cols();
124  for (ColIndex col(0); col < num_cols; ++col) {
125  const Fractional value = variable_values_[col];
126  matrix_.ColumnAddMultipleToDenseColumn(col, value, &scratchpad_.values);
127  }
128  return InfinityNorm(scratchpad_.values);
129 }
130 
132  SCOPED_TIME_STAT(&stats_);
133  Fractional primal_infeasibility = 0.0;
134  const ColIndex num_cols = matrix_.num_cols();
135  for (ColIndex col(0); col < num_cols; ++col) {
136  const Fractional col_infeasibility = std::max(
137  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
138  primal_infeasibility = std::max(primal_infeasibility, col_infeasibility);
139  }
140  return primal_infeasibility;
141 }
142 
144  SCOPED_TIME_STAT(&stats_);
145  Fractional sum = 0.0;
146  const ColIndex num_cols = matrix_.num_cols();
147  for (ColIndex col(0); col < num_cols; ++col) {
148  const Fractional col_infeasibility = std::max(
149  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
150  sum += std::max(0.0, col_infeasibility);
151  }
152  return sum;
153 }
154 
156  ColIndex entering_col, Fractional step) {
157  SCOPED_TIME_STAT(&stats_);
158  DCHECK(IsFinite(step));
159 
160  // Note(user): Some positions are ignored during the primal ratio test:
161  // - The rows for which direction_[row] < tolerance.
162  // - The non-zeros of direction_ignored_position_ in case of degeneracy.
163  // Such positions may result in basic variables going out of their bounds by
164  // more than the allowed tolerance. We could choose not to update these
165  // variables or not make them take out-of-bound values, but this would
166  // introduce artificial errors.
167 
168  // Note that there is no need to call variables_info_.Update() on basic
169  // variables when they change values. Note also that the status of
170  // entering_col will be updated later.
171  for (const auto e : direction) {
172  const ColIndex col = basis_[e.row()];
173  variable_values_[col] -= e.coefficient() * step;
174  }
175  variable_values_[entering_col] += step;
176 }
177 
179  const std::vector<ColIndex>& cols_to_update, bool update_basic_variables) {
180  SCOPED_TIME_STAT(&stats_);
181  if (!update_basic_variables) {
182  for (ColIndex col : cols_to_update) {
184  }
185  return;
186  }
187 
188  const RowIndex num_rows = matrix_.num_rows();
189  initially_all_zero_scratchpad_.values.resize(num_rows, 0.0);
190  DCHECK(IsAllZero(initially_all_zero_scratchpad_.values));
191  initially_all_zero_scratchpad_.ClearSparseMask();
192  bool use_dense = false;
193  for (ColIndex col : cols_to_update) {
194  const Fractional old_value = variable_values_[col];
196  if (use_dense) {
198  col, variable_values_[col] - old_value,
199  &initially_all_zero_scratchpad_.values);
200  } else {
202  col, variable_values_[col] - old_value,
203  &initially_all_zero_scratchpad_);
204  use_dense = initially_all_zero_scratchpad_.ShouldUseDenseIteration();
205  }
206  }
207  initially_all_zero_scratchpad_.ClearSparseMask();
208  initially_all_zero_scratchpad_.ClearNonZerosIfTooDense();
209 
210  basis_factorization_.RightSolve(&initially_all_zero_scratchpad_);
211  if (initially_all_zero_scratchpad_.non_zeros.empty()) {
212  for (RowIndex row(0); row < num_rows; ++row) {
213  variable_values_[basis_[row]] -= initially_all_zero_scratchpad_[row];
214  }
215  initially_all_zero_scratchpad_.values.AssignToZero(num_rows);
217  return;
218  }
219 
220  for (const auto e : initially_all_zero_scratchpad_) {
221  variable_values_[basis_[e.row()]] -= e.coefficient();
222  initially_all_zero_scratchpad_[e.row()] = 0.0;
223  }
224  UpdateDualPrices(initially_all_zero_scratchpad_.non_zeros);
225  initially_all_zero_scratchpad_.non_zeros.clear();
226 }
227 
228 void VariableValues::RecomputeDualPrices(bool put_more_importance_on_norm) {
229  SCOPED_TIME_STAT(&stats_);
230  const RowIndex num_rows = matrix_.num_rows();
231  dual_prices_->ClearAndResize(num_rows);
232  dual_prices_->StartDenseUpdates();
233 
234  put_more_importance_on_norm_ = put_more_importance_on_norm;
235  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
236  const DenseColumn& squared_norms = dual_edge_norms_->GetEdgeSquaredNorms();
237  if (put_more_importance_on_norm) {
238  for (RowIndex row(0); row < num_rows; ++row) {
239  const ColIndex col = basis_[row];
240  const Fractional infeasibility = std::max(
241  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
242  if (infeasibility > tolerance) {
243  dual_prices_->DenseAddOrUpdate(
244  row, std::abs(infeasibility) / squared_norms[row]);
245  }
246  }
247  } else {
248  for (RowIndex row(0); row < num_rows; ++row) {
249  const ColIndex col = basis_[row];
250  const Fractional infeasibility = std::max(
251  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
252  if (infeasibility > tolerance) {
253  dual_prices_->DenseAddOrUpdate(
254  row, Square(infeasibility) / squared_norms[row]);
255  }
256  }
257  }
258 }
259 
260 void VariableValues::UpdateDualPrices(absl::Span<const RowIndex> rows) {
261  if (dual_prices_->Size() != matrix_.num_rows()) {
262  RecomputeDualPrices(put_more_importance_on_norm_);
263  return;
264  }
265 
266  // Note(user): this is the same as the code in RecomputeDualPrices(), but we
267  // do need the clear part.
268  SCOPED_TIME_STAT(&stats_);
269  const Fractional tolerance = parameters_.primal_feasibility_tolerance();
270  const DenseColumn& squared_norms = dual_edge_norms_->GetEdgeSquaredNorms();
271  if (put_more_importance_on_norm_) {
272  for (const RowIndex row : rows) {
273  const ColIndex col = basis_[row];
274  const Fractional infeasibility = std::max(
275  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
276  if (infeasibility > tolerance) {
277  dual_prices_->AddOrUpdate(row,
278  std::abs(infeasibility) / squared_norms[row]);
279  } else {
280  dual_prices_->Remove(row);
281  }
282  }
283  } else {
284  for (const RowIndex row : rows) {
285  const ColIndex col = basis_[row];
286  const Fractional infeasibility = std::max(
287  GetUpperBoundInfeasibility(col), GetLowerBoundInfeasibility(col));
288  if (infeasibility > tolerance) {
289  dual_prices_->AddOrUpdate(row,
290  Square(infeasibility) / squared_norms[row]);
291  } else {
292  dual_prices_->Remove(row);
293  }
294  }
295  }
296 }
297 
298 } // namespace glop
299 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
void ColumnAddMultipleToSparseScatteredColumn(ColIndex col, Fractional multiplier, ScatteredColumn *column) const
Definition: sparse.h:442
void ColumnAddMultipleToDenseColumn(ColIndex col, Fractional multiplier, DenseColumn *dense_column) const
Definition: sparse.h:428
void AddOrUpdate(Index position, Fractional value)
Definition: pricing.h:188
void DenseAddOrUpdate(Index position, Fractional value)
Definition: pricing.h:179
void UpdateDualPrices(absl::Span< const RowIndex > row)
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 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:186
RowIndex row
Definition: markowitz.cc:185
Fractional Square(Fractional f)
Fractional InfinityNorm(const DenseColumn &v)
bool IsAllZero(const Container &input)
constexpr double kInfinity
Definition: lp_types.h:88
bool IsFinite(Fractional value)
Definition: lp_types.h:95
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:439
bool ShouldUseDenseIteration(double ratio_for_using_dense_representation) const
void ClearNonZerosIfTooDense(double ratio_for_using_dense_representation)
StrictITIVector< Index, Fractional > values