Google OR-Tools v9.11
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-2024 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 "absl/log/check.h"
17#include "ortools/glop/parameters.pb.h"
23
24namespace operations_research {
25namespace glop {
26
27void ComputeSlackVariablesValues(const LinearProgram& linear_program,
28 DenseRow* values) {
29 DCHECK(values);
30 DCHECK_EQ(linear_program.num_variables(), values->size());
31
32 // If there are no slack variable, we can give up.
33 if (linear_program.GetFirstSlackVariable() == kInvalidCol) return;
34
35 const auto& transposed_matrix = linear_program.GetTransposeSparseMatrix();
36 for (RowIndex row(0); row < linear_program.num_constraints(); row++) {
37 const ColIndex slack_variable = linear_program.GetSlackVariable(row);
38
39 if (slack_variable == kInvalidCol) continue;
40
41 DCHECK_EQ(0.0, linear_program.constraint_lower_bounds()[row]);
42 DCHECK_EQ(0.0, linear_program.constraint_upper_bounds()[row]);
43
44 const RowIndex transposed_slack = ColToRowIndex(slack_variable);
45 Fractional activation = 0.0;
46 // Row in the initial matrix (column in the transposed).
47 const SparseColumn& sparse_row =
48 transposed_matrix.column(RowToColIndex(row));
49 for (const auto& entry : sparse_row) {
50 if (transposed_slack == entry.index()) continue;
51 activation +=
52 (*values)[RowToColIndex(entry.index())] * entry.coefficient();
53 }
54 (*values)[slack_variable] = -activation;
55 }
56}
57
58// This is separated from the LinearProgram class because of a cyclic dependency
59// when scaling as an LP.
61 // Create GlopParameters proto to get default scaling algorithm.
62 GlopParameters params;
63 Scale(lp, scaler, params.scaling_method());
64}
65
66// This is separated from LinearProgram class because of a cyclic dependency
67// when scaling as an LP.
69 GlopParameters::ScalingAlgorithm scaling_method) {
70 scaler->Init(&lp->matrix_);
71 scaler->Scale(
72 scaling_method); // Compute R and C, and replace the matrix A by R.A.C
73 scaler->ScaleRowVector(false,
74 &lp->objective_coefficients_); // oc = oc.C
75 scaler->ScaleRowVector(true,
76 &lp->variable_upper_bounds_); // cl = cl.C^-1
77 scaler->ScaleRowVector(true,
78 &lp->variable_lower_bounds_); // cu = cu.C^-1
79 scaler->ScaleColumnVector(false, &lp->constraint_upper_bounds_); // rl = R.rl
80 scaler->ScaleColumnVector(false, &lp->constraint_lower_bounds_); // ru = R.ru
81 lp->transpose_matrix_is_consistent_ = false;
82}
83
84void LpScalingHelper::Scale(LinearProgram* lp) { Scale(GlopParameters(), lp); }
85
86void LpScalingHelper::Scale(const GlopParameters& params, LinearProgram* lp) {
87 scaler_.Clear();
88 ::operations_research::glop::Scale(lp, &scaler_, params.scaling_method());
89 bound_scaling_factor_ = 1.0 / lp->ScaleBounds();
90 objective_scaling_factor_ = 1.0 / lp->ScaleObjective(params.cost_scaling());
91}
92
94 scaler_.Clear();
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 scaler_.ColUnscalingFactor(col) * bound_scaling_factor_;
103}
104
106 Fractional value) const {
107 return value * scaler_.ColUnscalingFactor(col) * bound_scaling_factor_;
108}
109
111 Fractional value) const {
112 // The reduced cost move like the objective and the col scale.
113 return value / scaler_.ColUnscalingFactor(col) * objective_scaling_factor_;
114}
115
117 Fractional value) const {
118 // The dual value move like the objective and the inverse of the row scale.
119 return value * (scaler_.RowUnscalingFactor(row) * objective_scaling_factor_);
120}
121
123 Fractional value) const {
124 // The activity move with the row_scale and the bound_scaling_factor.
125 return value / scaler_.RowUnscalingFactor(row) * bound_scaling_factor_;
126}
127
129 Fractional value) const {
130 // Just the opposite of ScaleVariableValue().
131 return value / (scaler_.ColUnscalingFactor(col) * bound_scaling_factor_);
132}
133
135 Fractional value) const {
136 // The reduced cost move like the objective and the col scale.
137 return value * scaler_.ColUnscalingFactor(col) / objective_scaling_factor_;
138}
139
141 Fractional value) const {
142 // The dual value move like the objective and the inverse of the row scale.
143 return value / (scaler_.RowUnscalingFactor(row) * objective_scaling_factor_);
144}
145
147 Fractional value) const {
148 // The activity move with the row_scale and the bound_scaling_factor.
149 return value * scaler_.RowUnscalingFactor(row) / bound_scaling_factor_;
150}
151
153 ColIndex basis_col, ScatteredRow* left_inverse) const {
154 const Fractional global_factor = scaler_.ColUnscalingFactor(basis_col);
155
156 // We have left_inverse * [RowScale * B * ColScale] = unit_row.
157 if (left_inverse->non_zeros.empty()) {
158 const ColIndex num_rows = left_inverse->values.size();
159 for (ColIndex col(0); col < num_rows; ++col) {
160 left_inverse->values[col] /=
161 scaler_.RowUnscalingFactor(ColToRowIndex(col)) * global_factor;
162 }
163 } else {
164 for (const ColIndex col : left_inverse->non_zeros) {
165 left_inverse->values[col] /=
166 scaler_.RowUnscalingFactor(ColToRowIndex(col)) * global_factor;
167 }
168 }
169}
170
172 const RowToColMapping& basis, ColIndex col,
173 ScatteredColumn* right_inverse) const {
174 const Fractional global_factor = scaler_.ColScalingFactor(col);
175
176 // [RowScale * B * BColScale] * inverse = RowScale * column * ColScale.
177 // That is B * (BColScale * inverse) = column * ColScale[col].
178 if (right_inverse->non_zeros.empty()) {
179 const RowIndex num_rows = right_inverse->values.size();
180 for (RowIndex row(0); row < num_rows; ++row) {
181 right_inverse->values[row] /=
182 scaler_.ColUnscalingFactor(basis[row]) * global_factor;
183 }
184 } else {
185 for (const RowIndex row : right_inverse->non_zeros) {
186 right_inverse->values[row] /=
187 scaler_.ColUnscalingFactor(basis[row]) * global_factor;
188 }
189 }
190}
191
192} // namespace glop
193} // namespace operations_research
const DenseColumn & constraint_lower_bounds() const
Definition lp_data.h:223
const SparseMatrix & GetTransposeSparseMatrix() const
Definition lp_data.cc:385
ColIndex GetSlackVariable(RowIndex row) const
Definition lp_data.cc:766
Fractional ScaleObjective(GlopParameters::CostScalingAlgorithm method)
Definition lp_data.cc:1199
const DenseColumn & constraint_upper_bounds() const
Definition lp_data.h:226
ColIndex num_variables() const
Returns the number of variables.
Definition lp_data.h:213
RowIndex num_constraints() const
Returns the number of constraints.
Definition lp_data.h:216
void UnscaleUnitRowLeftSolve(ColIndex basis_col, ScatteredRow *left_inverse) const
Fractional ScaleVariableValue(ColIndex col, Fractional value) const
Transforms value from unscaled domain to the scaled one.
Fractional UnscaleDualValue(RowIndex row, Fractional value) const
Fractional UnscaleConstraintActivity(RowIndex row, Fractional value) const
void Clear()
Clear all scaling coefficients.
Fractional ScaleDualValue(RowIndex row, Fractional value) const
void Scale(LinearProgram *lp)
Scale the given LP.
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
Transforms corresponding value from the scaled domain to the original one.
Fractional ScaleReducedCost(ColIndex col, Fractional value) const
void UnscaleColumnRightSolve(const RowToColMapping &basis, ColIndex col, ScatteredColumn *right_inverse) const
Unscale a col vector v such that B.c = matrix_column_col.
void ScaleColumnVector(bool up, DenseColumn *column_vector) const
void ScaleRowVector(bool up, DenseRow *row_vector) const
Fractional ColScalingFactor(ColIndex col) const
Fractional RowUnscalingFactor(RowIndex row) const
void Scale(GlopParameters::ScalingAlgorithm method)
Scales the matrix.
Fractional ColUnscalingFactor(ColIndex col) const
int64_t value
ColIndex col
Definition markowitz.cc:187
RowIndex row
Definition markowitz.cc:186
constexpr ColIndex kInvalidCol(-1)
void ComputeSlackVariablesValues(const LinearProgram &linear_program, DenseRow *values)
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
Definition lp_types.h:54
RowIndex ColToRowIndex(ColIndex col)
Get the RowIndex corresponding to the row # col.
Definition lp_types.h:57
void Scale(LinearProgram *lp, SparseMatrixScaler *scaler)
In SWIG mode, we don't want anything besides these top-level includes.
StrictITIVector< Index, Fractional > values