22 #include "absl/strings/str_format.h"
34 : matrix_(nullptr), row_scale_(), col_scale_() {}
37 DCHECK(matrix !=
nullptr);
51 return row < row_scale_.
size() ? row_scale_[
row] : 1.0;
56 return col < col_scale_.
size() ? col_scale_[
col] : 1.0;
67 std::string SparseMatrixScaler::DebugInformationString()
const {
71 DCHECK(!row_scale_.
empty());
72 DCHECK(!col_scale_.
empty());
76 const Fractional dynamic_range = max_magnitude / min_magnitude;
77 std::string output = absl::StrFormat(
78 "Min magnitude = %g, max magnitude = %g\n"
79 "Dynamic range = %g\n"
81 "Minimum row scale = %g, maximum row scale = %g\n"
82 "Minimum col scale = %g, maximum col scale = %g\n",
83 min_magnitude, max_magnitude, dynamic_range,
85 *std::min_element(row_scale_.
begin(), row_scale_.
end()),
86 *std::max_element(row_scale_.
begin(), row_scale_.
end()),
87 *std::min_element(col_scale_.
begin(), col_scale_.
end()),
88 *std::max_element(col_scale_.
begin(), col_scale_.
end()));
99 DCHECK(matrix_ !=
nullptr);
103 if (min_magnitude == 0.0) {
104 DCHECK_EQ(0.0, max_magnitude);
107 VLOG(1) <<
"Before scaling:\n" << DebugInformationString();
108 if (method == GlopParameters::LINEAR_PROGRAM) {
111 if (lp_status.
ok()) {
119 const Fractional dynamic_range = max_magnitude / min_magnitude;
120 const Fractional kMaxDynamicRangeForGeometricScaling = 1e20;
121 if (dynamic_range < kMaxDynamicRangeForGeometricScaling) {
122 const int kScalingIterations = 4;
124 for (
int iteration = 0; iteration < kScalingIterations; ++iteration) {
128 VLOG(1) <<
"Geometric scaling iteration " << iteration
129 <<
". Rows scaled = " << num_rows_scaled
130 <<
", columns scaled = " << num_cols_scaled <<
"\n";
131 VLOG(1) << DebugInformationString();
132 if (variance < kVarianceThreshold ||
133 (num_cols_scaled == 0 && num_rows_scaled == 0)) {
140 VLOG(1) <<
"Equilibration step: Rows scaled = " << rows_equilibrated
141 <<
", columns scaled = " << cols_equilibrated <<
"\n";
142 VLOG(1) << DebugInformationString();
152 for (I i(0); i < size; ++i) {
153 (*vector_to_scale)[i] *= scale[i];
156 for (I i(0); i < size; ++i) {
157 (*vector_to_scale)[i] /= scale[i];
162 template <
typename InputIndexType>
163 ColIndex CreateOrGetScaleIndex(
164 InputIndexType num, LinearProgram* lp,
166 if ((*scale_var_indices)[num] == -1) {
167 (*scale_var_indices)[num] = lp->CreateNewVariable();
169 return (*scale_var_indices)[num];
174 DCHECK(row_vector !=
nullptr);
175 ScaleVector(col_scale_, up, row_vector);
180 DCHECK(column_vector !=
nullptr);
181 ScaleVector(row_scale_, up, column_vector);
185 DCHECK(matrix_ !=
nullptr);
189 const ColIndex num_cols = matrix_->
num_cols();
190 for (ColIndex
col(0);
col < num_cols; ++
col) {
192 const Fractional magnitude = fabs(e.coefficient());
193 if (magnitude != 0.0) {
194 sigma_square += magnitude * magnitude;
195 sigma_abs += magnitude;
200 if (n == 0.0)
return 0.0;
206 return (sigma_square - sigma_abs * sigma_abs / n) / n;
215 DCHECK(matrix_ !=
nullptr);
218 const ColIndex num_cols = matrix_->
num_cols();
219 for (ColIndex
col(0);
col < num_cols; ++
col) {
221 const Fractional magnitude = fabs(e.coefficient());
222 const RowIndex
row = e.row();
223 if (magnitude != 0.0) {
229 const RowIndex num_rows = matrix_->
num_rows();
231 for (RowIndex
row(0);
row < num_rows; ++
row) {
232 if (max_in_row[
row] == 0.0) {
233 scaling_factor[
row] = 1.0;
236 scaling_factor[
row] = sqrt(max_in_row[
row] * min_in_row[
row]);
239 return ScaleMatrixRows(scaling_factor);
243 DCHECK(matrix_ !=
nullptr);
244 ColIndex num_cols_scaled(0);
245 const ColIndex num_cols = matrix_->
num_cols();
246 for (ColIndex
col(0);
col < num_cols; ++
col) {
250 const Fractional magnitude = fabs(e.coefficient());
251 if (magnitude != 0.0) {
252 max_in_col =
std::max(max_in_col, magnitude);
253 min_in_col =
std::min(min_in_col, magnitude);
256 if (max_in_col != 0.0) {
258 ScaleMatrixColumn(
col, factor);
262 return num_cols_scaled;
271 DCHECK(matrix_ !=
nullptr);
272 const RowIndex num_rows = matrix_->
num_rows();
274 const ColIndex num_cols = matrix_->
num_cols();
275 for (ColIndex
col(0);
col < num_cols; ++
col) {
277 const Fractional magnitude = fabs(e.coefficient());
278 if (magnitude != 0.0) {
279 const RowIndex
row = e.row();
284 for (RowIndex
row(0);
row < num_rows; ++
row) {
285 if (max_magnitude[
row] == 0.0) {
286 max_magnitude[
row] = 1.0;
289 return ScaleMatrixRows(max_magnitude);
293 DCHECK(matrix_ !=
nullptr);
294 ColIndex num_cols_scaled(0);
295 const ColIndex num_cols = matrix_->
num_cols();
296 for (ColIndex
col(0);
col < num_cols; ++
col) {
298 if (max_magnitude != 0.0) {
299 ScaleMatrixColumn(
col, max_magnitude);
303 return num_cols_scaled;
306 RowIndex SparseMatrixScaler::ScaleMatrixRows(
const DenseColumn& factors) {
308 DCHECK(matrix_ !=
nullptr);
309 const RowIndex num_rows = matrix_->
num_rows();
310 DCHECK_EQ(num_rows, factors.
size());
311 RowIndex num_rows_scaled(0);
312 for (RowIndex
row(0);
row < num_rows; ++
row) {
314 DCHECK_NE(0.0, factor);
317 row_scale_[
row] *= factor;
321 const ColIndex num_cols = matrix_->
num_cols();
322 for (ColIndex
col(0);
col < num_cols; ++
col) {
325 column->ComponentWiseDivide(factors);
329 return num_rows_scaled;
332 void SparseMatrixScaler::ScaleMatrixColumn(ColIndex
col,
Fractional factor) {
334 DCHECK(matrix_ !=
nullptr);
335 col_scale_[
col] *= factor;
336 DCHECK_NE(0.0, factor);
340 column->DivideByConstant(factor);
346 DCHECK(matrix_ !=
nullptr);
347 const ColIndex num_cols = matrix_->
num_cols();
348 for (ColIndex
col(0);
col < num_cols; ++
col) {
350 DCHECK_NE(0.0, column_scale);
354 column->MultiplyByConstant(column_scale);
355 column->ComponentWiseMultiply(row_scale_);
361 DCHECK(matrix_ !=
nullptr);
363 auto linear_program = std::make_unique<LinearProgram>();
364 GlopParameters params;
365 auto simplex = std::make_unique<RevisedSimplex>();
366 simplex->SetParameters(params);
390 const ColIndex beta = linear_program->CreateNewVariable();
393 linear_program->SetObjectiveCoefficient(beta, 1);
395 const ColIndex num_cols = matrix_->
num_cols();
396 for (ColIndex
col(0);
col < num_cols; ++
col) {
399 const ColIndex column_scale = CreateOrGetScaleIndex<ColIndex>(
400 col, linear_program.get(), &col_scale_var_indices);
402 for (EntryIndex i :
column->AllEntryIndices()) {
404 log2(std::abs(
column->EntryCoefficient(i)));
405 const RowIndex
row =
column->EntryRow(i);
407 const ColIndex row_scale = CreateOrGetScaleIndex<RowIndex>(
408 row, linear_program.get(), &row_scale_var_indices);
421 const RowIndex positive_constraint =
422 linear_program->CreateNewConstraint();
424 linear_program->SetConstraintBounds(positive_constraint, -log_magnitude,
427 linear_program->SetCoefficient(positive_constraint, row_scale, 1);
429 linear_program->SetCoefficient(positive_constraint, column_scale, 1);
431 linear_program->SetCoefficient(positive_constraint, beta, 1);
434 const RowIndex negative_constraint =
435 linear_program->CreateNewConstraint();
437 linear_program->SetConstraintBounds(negative_constraint, -
kInfinity,
440 linear_program->SetCoefficient(negative_constraint, row_scale, 1);
442 linear_program->SetCoefficient(negative_constraint, column_scale, 1);
444 linear_program->SetCoefficient(negative_constraint, beta, -1);
449 linear_program->AddSlackVariablesWhereNecessary(
false);
450 const Status simplex_status =
452 if (!simplex_status.
ok()) {
453 return simplex_status;
459 const ColIndex num_cols = matrix_->
num_cols();
460 for (ColIndex
col(0);
col < num_cols; ++
col) {
462 exp2(-simplex->GetVariableValue(CreateOrGetScaleIndex<ColIndex>(
463 col, linear_program.get(), &col_scale_var_indices)));
464 ScaleMatrixColumn(
col, column_scale);
466 const RowIndex num_rows = matrix_->
num_rows();
468 for (RowIndex
row(0);
row < num_rows; ++
row) {
470 exp2(-simplex->GetVariableValue(CreateOrGetScaleIndex<RowIndex>(
471 row, linear_program.get(), &row_scale_var_indices)));
473 ScaleMatrixRows(row_scale);
void resize(size_type new_size)
static std::unique_ptr< TimeLimit > Infinite()
Creates a time limit object that uses infinite time for wall time, deterministic time and instruction...
SparseColumn * mutable_column(ColIndex col)
ColIndex num_cols() const
void ComputeMinAndMaxMagnitudes(Fractional *min_magnitude, Fractional *max_magnitude) const
RowIndex num_rows() const
const SparseColumn & column(ColIndex col) const
Fractional RowScalingFactor(RowIndex row) const
Fractional ColScalingFactor(ColIndex col) const
void ScaleColumnVector(bool up, DenseColumn *column_vector) const
void Init(SparseMatrix *matrix)
void ScaleRowVector(bool up, DenseRow *row_vector) const
ColIndex EquilibrateColumns()
RowIndex EquilibrateRows()
ColIndex ScaleColumnsGeometrically()
void Scale(GlopParameters::ScalingAlgorithm method)
Fractional ColUnscalingFactor(ColIndex col) const
Fractional RowUnscalingFactor(RowIndex row) const
RowIndex ScaleRowsGeometrically()
Fractional VarianceOfAbsoluteValueOfNonZeros() const
typename Iterator::Entry Entry
const std::string & error_message() const
void resize(IntType size)
constexpr ColIndex kInvalidCol(-1)
Fractional InfinityNorm(const DenseColumn &v)
Index ColToIntIndex(ColIndex col)
constexpr double kInfinity
Index RowToIntIndex(RowIndex row)
static double ToDouble(double f)
Collection of objects used to extend the Constraint Solver library.
#define RETURN_IF_NULL(x)
#define VLOG(verboselevel)