OR-Tools  9.3
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
19namespace operations_research {
20namespace 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
244void 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
int64_t max
Definition: alldiff_cst.cc:140
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:892
#define LOG(severity)
Definition: base/logging.h:420
#define DCHECK(condition)
Definition: base/logging.h:890
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:891
void ColumnAddMultipleToSparseScatteredColumn(ColIndex col, Fractional multiplier, ScatteredColumn *column) const
Definition: sparse.h:410
void ColumnAddMultipleToDenseColumn(ColIndex col, Fractional multiplier, DenseColumn *dense_column) const
Definition: sparse.h:398
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 ResetAllNonBasicVariableValues(const DenseRow &free_initial_values)
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 & GetVariableLowerBounds() const
const DenseBitRow & GetNotBasicBitRow() const
const VariableStatusRow & GetStatusRow() const
const DenseRow & GetVariableUpperBounds() 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