Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
lp_data_utils.cc
Go to the documentation of this file.
1// Copyright 2010-2025 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 <cstdlib>
18#include <limits>
19
20#include "absl/log/check.h"
21#include "absl/types/span.h"
28
29namespace operations_research {
30namespace glop {
31
32// This is separated from the LinearProgram class because of a cyclic dependency
33// when scaling as an LP.
35 // Create GlopParameters proto to get default scaling algorithm.
36 GlopParameters params;
37 Scale(lp, scaler, params.scaling_method());
38}
39
40// This is separated from LinearProgram class because of a cyclic dependency
41// when scaling as an LP.
43 GlopParameters::ScalingAlgorithm scaling_method) {
44 scaler->Init(&lp->matrix_);
45 scaler->Scale(
46 scaling_method); // Compute R and C, and replace the matrix A by R.A.C
47 scaler->ScaleRowVector(false,
48 &lp->objective_coefficients_); // oc = oc.C
49 scaler->ScaleRowVector(true,
50 &lp->variable_upper_bounds_); // cl = cl.C^-1
51 scaler->ScaleRowVector(true,
52 &lp->variable_lower_bounds_); // cu = cu.C^-1
53 scaler->ScaleColumnVector(false, &lp->constraint_upper_bounds_); // rl = R.rl
54 scaler->ScaleColumnVector(false, &lp->constraint_lower_bounds_); // ru = R.ru
55 lp->transpose_matrix_is_consistent_ = false;
56}
57
59
61 SparseMatrixScaler scaler;
63 bound_scaling_factor_ = 1.0 / lp->ScaleBounds();
64 objective_scaling_factor_ = 1.0 / lp->ScaleObjective(params.cost_scaling());
65
66 matrix_is_scaled_ = true;
67 row_unscaling_factors_ = scaler.row_scales();
68 col_unscaling_factors_ = scaler.col_scales();
69
70 // It is possible the scaler didn't do anything.
71 // we still allocate the vector though since we don't test that below.
72 row_unscaling_factors_.resize(lp->num_constraints(), 1.0);
73 col_unscaling_factors_.resize(lp->num_variables(), 1.0);
74}
75
77 absl::Span<const double> row_factors,
78 absl::Span<const double> col_factors) {
79 matrix_is_scaled_ = true;
80 const RowIndex num_rows(row_factors.size());
81 row_unscaling_factors_.resize(num_rows, 1.0);
82 for (RowIndex row(0); row < num_rows; ++row) {
83 row_unscaling_factors_[row] = 1.0 / row_factors[row.value()];
84 }
85
86 const ColIndex num_cols(col_factors.size());
87 col_unscaling_factors_.resize(num_cols, 1.0);
88 for (ColIndex col(0); col < num_cols; ++col) {
89 col_unscaling_factors_[col] = 1.0 / col_factors[col.value()];
90 }
91}
92
94 matrix_is_scaled_ = false;
95 bound_scaling_factor_ = 1.0;
96 objective_scaling_factor_ = 1.0;
97}
98
100 // During scaling a col was multiplied by ColScalingFactor() and the variable
101 // bounds divided by it.
102 return ColUnscalingFactor(col) * bound_scaling_factor_;
103}
104
106 if (!matrix_is_scaled_) return bound_scaling_factor_;
107 const ColIndex num_cols = col_unscaling_factors_.size();
108 if (col < num_cols) {
109 return col_unscaling_factors_[col] * bound_scaling_factor_;
110 }
111 return row_unscaling_factors_[ColToRowIndex(col - num_cols)] *
112 bound_scaling_factor_;
113}
114
116 Fractional value) const {
117 return value * ColUnscalingFactor(col) * bound_scaling_factor_;
118}
119
121 Fractional value) const {
122 // The reduced cost move like the objective and the col scale.
123 return value / ColUnscalingFactor(col) * objective_scaling_factor_;
124}
125
127 Fractional value) const {
128 // The dual value move like the objective and the inverse of the row scale.
129 return value * (RowUnscalingFactor(row) * objective_scaling_factor_);
130}
131
133 Fractional value) const {
134 // The activity move with the row_scale and the bound_scaling_factor.
135 return value / RowUnscalingFactor(row) * bound_scaling_factor_;
136}
137
139 Fractional value) const {
140 // Just the opposite of ScaleVariableValue().
141 return value / (ColUnscalingFactor(col) * bound_scaling_factor_);
142}
143
145 Fractional value) const {
146 // The reduced cost move like the objective and the col scale.
147 return value * ColUnscalingFactor(col) / objective_scaling_factor_;
148}
149
151 Fractional value) const {
152 // The dual value move like the objective and the inverse of the row scale.
153 return value / (RowUnscalingFactor(row) * objective_scaling_factor_);
154}
155
157 Fractional value) const {
158 // In the scaled domain, we are takeing a sum coeff * scaling * row,
159 // so to get the same effect in the unscaled domain, we want to multiply by
160 // (coeff * scaling).
161 return value / RowUnscalingFactor(row);
162}
163
165 Fractional value) const {
166 // The activity move with the row_scale and the bound_scaling_factor.
167 return value * RowUnscalingFactor(row) / bound_scaling_factor_;
168}
169
171 ColIndex basis_col, ScatteredRow* left_inverse) const {
172 const Fractional global_factor = ColUnscalingFactor(basis_col);
173
174 // We have left_inverse * [RowScale * B * ColScale] = unit_row.
175 if (left_inverse->non_zeros.empty()) {
176 const ColIndex num_rows = left_inverse->values.size();
177 for (ColIndex col(0); col < num_rows; ++col) {
178 left_inverse->values[col] /=
179 RowUnscalingFactor(ColToRowIndex(col)) * global_factor;
180 }
181 } else {
182 for (const ColIndex col : left_inverse->non_zeros) {
183 left_inverse->values[col] /=
184 RowUnscalingFactor(ColToRowIndex(col)) * global_factor;
185 }
186 }
187}
188
190 const RowToColMapping& basis, ColIndex col,
191 ScatteredColumn* right_inverse) const {
192 const Fractional global_factor = 1.0 / ColUnscalingFactor(col);
193
194 // [RowScale * B * BColScale] * inverse = RowScale * column * ColScale.
195 // That is B * (BColScale * inverse) = column * ColScale[col].
196 if (right_inverse->non_zeros.empty()) {
197 const RowIndex num_rows = right_inverse->values.size();
198 for (RowIndex row(0); row < num_rows; ++row) {
199 right_inverse->values[row] /=
200 ColUnscalingFactor(basis[row]) * global_factor;
201 }
202 } else {
203 for (const RowIndex row : right_inverse->non_zeros) {
204 right_inverse->values[row] /=
205 ColUnscalingFactor(basis[row]) * global_factor;
206 }
207 }
208}
209
211 Fractional sum = 0.0;
212 int num_terms = 0;
213 for (const Fractional f : *objective) {
214 if (f == 0) continue;
215 ++num_terms;
216 sum += std::abs(f);
217 }
218 if (num_terms == 0) {
219 objective_scaling_factor_ = 1.0;
220 return;
221 }
222
223 const Fractional average = sum / static_cast<double>(num_terms);
224 objective_scaling_factor_ = 1.0 / average;
225 for (Fractional& f : *objective) {
226 f *= objective_scaling_factor_;
227 }
228}
229
231 DenseRow* lower_bounds) {
232 const double infinity = std::numeric_limits<double>::infinity();
233 Fractional min_magnitude = infinity;
234 Fractional max_magnitude = 0.0;
235 for (const Fractional f : *lower_bounds) {
236 const Fractional m = std::abs(f);
237 if (m == 0 || m == infinity) continue;
238 min_magnitude = std::min(min_magnitude, m);
239 max_magnitude = std::max(max_magnitude, m);
240 }
241 for (const Fractional f : *upper_bounds) {
242 const Fractional m = std::abs(f);
243 if (m == 0 || m == infinity) continue;
244 min_magnitude = std::min(min_magnitude, m);
245 max_magnitude = std::max(max_magnitude, m);
246 }
247
248 bound_scaling_factor_ = 1.0;
249 if (min_magnitude != infinity) {
250 CHECK_LE(min_magnitude, max_magnitude);
251 if (min_magnitude > 1.0) {
252 bound_scaling_factor_ = 1.0 / min_magnitude;
253 } else if (max_magnitude < 1.0) {
254 bound_scaling_factor_ = 1.0 / max_magnitude;
255 }
256 }
257
258 if (bound_scaling_factor_ == 1.0) return;
259 for (Fractional& f : *lower_bounds) {
260 f *= bound_scaling_factor_;
261 }
262 for (Fractional& f : *upper_bounds) {
263 f *= bound_scaling_factor_;
264 }
265}
266
267} // namespace glop
268} // namespace operations_research
GlopParameters_ScalingAlgorithm ScalingAlgorithm
::operations_research::glop::GlopParameters_CostScalingAlgorithm cost_scaling() const
::operations_research::glop::GlopParameters_ScalingAlgorithm scaling_method() const
Fractional ScaleObjective(GlopParameters::CostScalingAlgorithm method)
Definition lp_data.cc:1199
void UnscaleUnitRowLeftSolve(ColIndex basis_col, ScatteredRow *left_inverse) const
void AverageCostScaling(DenseRow *objective)
void ConfigureFromFactors(absl::Span< const double > row_factors, absl::Span< const double > col_factors)
Fractional VariableScalingFactorWithSlack(ColIndex col) const
Fractional ScaleVariableValue(ColIndex col, Fractional value) const
Fractional UnscaleDualValue(RowIndex row, Fractional value) const
void ContainOneBoundScaling(DenseRow *upper_bounds, DenseRow *lower_bounds)
Fractional UnscaleConstraintActivity(RowIndex row, Fractional value) const
Fractional UnscaleLeftSolveValue(RowIndex row, Fractional value) const
Fractional ScaleDualValue(RowIndex row, Fractional value) const
Fractional ScaleConstraintActivity(RowIndex row, Fractional value) const
Fractional UnscaleReducedCost(ColIndex col, Fractional value) const
Fractional VariableScalingFactor(ColIndex col) const
Fractional UnscaleVariableValue(ColIndex col, Fractional value) const
Fractional ScaleReducedCost(ColIndex col, Fractional value) const
void UnscaleColumnRightSolve(const RowToColMapping &basis, ColIndex col, ScatteredColumn *right_inverse) const
void ScaleColumnVector(bool up, DenseColumn *column_vector) const
void ScaleRowVector(bool up, DenseRow *row_vector) const
void Scale(GlopParameters::ScalingAlgorithm method)
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Definition lp_types.h:394
RowIndex ColToRowIndex(ColIndex col)
Definition lp_types.h:57
void Scale(LinearProgram *lp, SparseMatrixScaler *scaler)
StrictITIVector< ColIndex, Fractional > DenseRow
Definition lp_types.h:351
OR-Tools root namespace.
StrictITIVector< Index, Fractional > values