Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
lu_factorization.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 <cstddef>
18#include <cstdlib>
19#include <vector>
20
21#include "absl/log/check.h"
22#include "absl/types/span.h"
25
26namespace operations_research {
27namespace glop {
28
30 : is_identity_factorization_(true),
31 col_perm_(),
32 inverse_col_perm_(),
33 row_perm_(),
34 inverse_row_perm_() {}
35
37 SCOPED_TIME_STAT(&stats_);
38 lower_.Reset(RowIndex(0), ColIndex(0));
39 upper_.Reset(RowIndex(0), ColIndex(0));
40 transpose_upper_.Reset(RowIndex(0), ColIndex(0));
41 transpose_lower_.Reset(RowIndex(0), ColIndex(0));
42 is_identity_factorization_ = true;
43 col_perm_.clear();
44 row_perm_.clear();
45 inverse_row_perm_.clear();
46 inverse_col_perm_.clear();
47}
48
50 const CompactSparseMatrixView& matrix) {
51 SCOPED_TIME_STAT(&stats_);
52 Clear();
53 if (matrix.num_rows().value() != matrix.num_cols().value()) {
54 GLOP_RETURN_AND_LOG_ERROR(Status::ERROR_LU, "Not a square matrix!!");
55 }
56
58 markowitz_.ComputeLU(matrix, &row_perm_, &col_perm_, &lower_, &upper_));
59 inverse_col_perm_.PopulateFromInverse(col_perm_);
60 inverse_row_perm_.PopulateFromInverse(row_perm_);
61 ComputeTransposeUpper();
62 ComputeTransposeLower();
63
64 is_identity_factorization_ = false;
66 stats_.lu_fill_in.Add(GetFillInPercentage(matrix));
67 stats_.basis_num_entries.Add(matrix.num_entries().value());
68 });
69
70 // Note(user): This might fail on badly scaled matrices. I still prefer to
71 // keep it as a DCHECK() for tests though, but I only test it for small
72 // matrices.
73 DCHECK(matrix.num_rows() > 100 ||
74 CheckFactorization(matrix, Fractional(1e-6)));
75 return Status::OK();
76}
77
79 const CompactSparseMatrix& matrix,
80 const std::vector<ColIndex>& candidates) {
81 CompactSparseMatrixView view(&matrix, &candidates);
82 (void)markowitz_.ComputeRowAndColumnPermutation(view, &row_perm_, &col_perm_);
83
84 // Starts by the missing slacks.
85 RowToColMapping basis;
86 for (RowIndex row(0); row < matrix.num_rows(); ++row) {
87 if (row_perm_[row] == kInvalidRow) {
88 // Add the slack for this row.
89 basis.push_back(matrix.num_cols() +
90 RowToColIndex(row - matrix.num_rows()));
91 }
92 }
93
94 // Then add the used candidate columns.
95 CHECK_EQ(col_perm_.size(), candidates.size());
96 for (int i = 0; i < col_perm_.size(); ++i) {
97 if (col_perm_[ColIndex(i)] != kInvalidCol) {
98 basis.push_back(candidates[i]);
99 }
100 }
101
102 return basis;
103}
104
106 return markowitz_.DeterministicTimeOfLastFactorization();
107}
108
110 SCOPED_TIME_STAT(&stats_);
111 if (is_identity_factorization_) return;
112
113 ApplyPermutation(row_perm_, *x, &dense_column_scratchpad_);
114 lower_.LowerSolve(&dense_column_scratchpad_);
115 upper_.UpperSolve(&dense_column_scratchpad_);
116 ApplyPermutation(inverse_col_perm_, dense_column_scratchpad_, x);
117}
118
120 SCOPED_TIME_STAT(&stats_);
121 if (is_identity_factorization_) return;
122
123 // We need to interpret y as a column for the permutation functions.
124 DenseColumn* const x = reinterpret_cast<DenseColumn*>(y);
125 ApplyInversePermutation(inverse_col_perm_, *x, &dense_column_scratchpad_);
126 upper_.TransposeUpperSolve(&dense_column_scratchpad_);
127 lower_.TransposeLowerSolve(&dense_column_scratchpad_);
128 ApplyInversePermutation(row_perm_, dense_column_scratchpad_, x);
129}
130
131namespace {
132// If non_zeros is empty, uses a dense algorithm to compute the squared L2
133// norm of the given column, otherwise do the same with a sparse version. In
134// both cases column is cleared.
135Fractional ComputeSquaredNormAndResetToZero(
136 absl::Span<const RowIndex> non_zeros, absl::Span<Fractional> column) {
137 Fractional sum = 0.0;
138 if (non_zeros.empty()) {
139 sum = SquaredNormAndResetToZero(column);
140 } else {
141 for (const RowIndex row : non_zeros) {
142 sum += Square(column[row.value()]);
143 (column)[row.value()] = 0.0;
144 }
145 }
146 return sum;
147}
148} // namespace
149
151 SCOPED_TIME_STAT(&stats_);
152 if (is_identity_factorization_) return SquaredNorm(a);
153
154 non_zero_rows_.clear();
155 const RowIndex num_rows = lower_.num_rows();
156 dense_zero_scratchpad_.resize(num_rows, 0.0);
157 DCHECK(IsAllZero(dense_zero_scratchpad_));
158
159 for (const SparseColumn::Entry e : a) {
160 const RowIndex permuted_row = row_perm_[e.row()];
161 dense_zero_scratchpad_[permuted_row] = e.coefficient();
162 non_zero_rows_.push_back(permuted_row);
163 }
164
165 lower_.ComputeRowsToConsiderInSortedOrder(&non_zero_rows_);
166 if (non_zero_rows_.empty()) {
167 lower_.LowerSolve(&dense_zero_scratchpad_);
168 } else {
169 lower_.HyperSparseSolve(&dense_zero_scratchpad_, &non_zero_rows_);
170 upper_.ComputeRowsToConsiderInSortedOrder(&non_zero_rows_);
171 }
172 if (non_zero_rows_.empty()) {
173 upper_.UpperSolve(&dense_zero_scratchpad_);
174 } else {
175 upper_.HyperSparseSolveWithReversedNonZeros(&dense_zero_scratchpad_,
176 &non_zero_rows_);
177 }
178 return ComputeSquaredNormAndResetToZero(
179 non_zero_rows_,
180 absl::MakeSpan(dense_zero_scratchpad_.data(), num_rows.value()));
181}
182
184 if (is_identity_factorization_) return 1.0;
185 SCOPED_TIME_STAT(&stats_);
186 const RowIndex permuted_row =
187 col_perm_.empty() ? row : ColToRowIndex(col_perm_[RowToColIndex(row)]);
188
189 non_zero_rows_.clear();
190 const RowIndex num_rows = lower_.num_rows();
191 dense_zero_scratchpad_.resize(num_rows, 0.0);
192 DCHECK(IsAllZero(dense_zero_scratchpad_));
193 dense_zero_scratchpad_[permuted_row] = 1.0;
194 non_zero_rows_.push_back(permuted_row);
195
196 transpose_upper_.ComputeRowsToConsiderInSortedOrder(&non_zero_rows_);
197 if (non_zero_rows_.empty()) {
198 transpose_upper_.LowerSolveStartingAt(RowToColIndex(permuted_row),
199 &dense_zero_scratchpad_);
200 } else {
201 transpose_upper_.HyperSparseSolve(&dense_zero_scratchpad_, &non_zero_rows_);
202 transpose_lower_.ComputeRowsToConsiderInSortedOrder(&non_zero_rows_);
203 }
204 if (non_zero_rows_.empty()) {
205 transpose_lower_.UpperSolve(&dense_zero_scratchpad_);
206 } else {
207 transpose_lower_.HyperSparseSolveWithReversedNonZeros(
208 &dense_zero_scratchpad_, &non_zero_rows_);
209 }
210 return ComputeSquaredNormAndResetToZero(
211 non_zero_rows_,
212 absl::MakeSpan(dense_zero_scratchpad_.data(), num_rows.value()));
213}
214
215namespace {
216// Returns whether 'b' is equal to 'a' permuted by the given row permutation
217// 'perm'.
218bool AreEqualWithPermutation(const DenseColumn& a, const DenseColumn& b,
219 const RowPermutation& perm) {
220 const RowIndex num_rows = perm.size();
221 for (RowIndex row(0); row < num_rows; ++row) {
222 if (a[row] != b[perm[row]]) return false;
223 }
224 return true;
225}
226} // namespace
227
229 ScatteredColumn* x) const {
230 SCOPED_TIME_STAT(&stats_);
231 if (!is_identity_factorization_) {
232 DCHECK(AreEqualWithPermutation(a, x->values, row_perm_));
233 lower_.ComputeRowsToConsiderInSortedOrder(&x->non_zeros);
234 if (x->non_zeros.empty()) {
235 lower_.LowerSolve(&x->values);
236 } else {
237 lower_.HyperSparseSolve(&x->values, &x->non_zeros);
238 }
239 }
240}
241
242template <typename Column>
243void LuFactorization::RightSolveLInternal(const Column& b,
244 ScatteredColumn* x) const {
245 // This code is equivalent to
246 // b.PermutedCopyToDenseVector(row_perm_, num_rows, x);
247 // but it also computes the first column index which does not correspond to an
248 // identity column of lower_ thus exploiting a bit the hyper-sparsity
249 // of b.
250 ColIndex first_column_to_consider(RowToColIndex(x->values.size()));
251 const ColIndex limit = lower_.GetFirstNonIdentityColumn();
252 for (const auto e : b) {
253 const RowIndex permuted_row = row_perm_[e.row()];
254 (*x)[permuted_row] = e.coefficient();
255 x->non_zeros.push_back(permuted_row);
256
257 // The second condition only works because the elements on the diagonal of
258 // lower_ are all equal to 1.0.
259 const ColIndex col = RowToColIndex(permuted_row);
260 if (col < limit || lower_.ColumnIsDiagonalOnly(col)) {
261 DCHECK_EQ(1.0, lower_.GetDiagonalCoefficient(col));
262 continue;
263 }
264 first_column_to_consider = std::min(first_column_to_consider, col);
265 }
266
267 lower_.ComputeRowsToConsiderInSortedOrder(&x->non_zeros);
268 x->non_zeros_are_sorted = true;
269 if (x->non_zeros.empty()) {
270 lower_.LowerSolveStartingAt(first_column_to_consider, &x->values);
271 } else {
272 lower_.HyperSparseSolve(&x->values, &x->non_zeros);
273 }
274}
275
277 ScatteredColumn* x) const {
278 SCOPED_TIME_STAT(&stats_);
279 DCHECK(IsAllZero(x->values));
280 x->non_zeros.clear();
281 if (is_identity_factorization_) {
282 for (const ColumnView::Entry e : b) {
283 (*x)[e.row()] = e.coefficient();
284 x->non_zeros.push_back(e.row());
285 }
286 return;
287 }
288
289 RightSolveLInternal(b, x);
290}
291
293 if (is_identity_factorization_) return;
294 if (x->non_zeros.empty()) {
295 PermuteWithScratchpad(row_perm_, &dense_zero_scratchpad_, &x->values);
296 lower_.LowerSolve(&x->values);
297 return;
298 }
299
300 PermuteWithKnownNonZeros(row_perm_, &dense_zero_scratchpad_, &x->values,
301 &x->non_zeros);
302 lower_.ComputeRowsToConsiderInSortedOrder(&x->non_zeros);
303 x->non_zeros_are_sorted = true;
304 if (x->non_zeros.empty()) {
305 lower_.LowerSolve(&x->values);
306 } else {
307 lower_.HyperSparseSolve(&x->values, &x->non_zeros);
308 }
309}
310
312 ScatteredColumn* x) const {
313 SCOPED_TIME_STAT(&stats_);
314 DCHECK(IsAllZero(x->values));
315 x->non_zeros.clear();
316
317 if (is_identity_factorization_) {
318 *x = b;
319 return;
320 }
321
322 if (b.non_zeros.empty()) {
323 *x = b;
324 return RightSolveLWithNonZeros(x);
325 }
326
327 RightSolveLInternal(b, x);
328}
329
331 SCOPED_TIME_STAT(&stats_);
332 CHECK(col_perm_.empty());
333 if (is_identity_factorization_) return;
334
335 DenseColumn* const x = reinterpret_cast<DenseColumn*>(&y->values);
336 RowIndexVector* const nz = reinterpret_cast<RowIndexVector*>(&y->non_zeros);
337 transpose_upper_.ComputeRowsToConsiderInSortedOrder(nz);
338 y->non_zeros_are_sorted = true;
339 if (nz->empty()) {
340 upper_.TransposeUpperSolve(x);
341 } else {
342 upper_.TransposeHyperSparseSolve(x, nz);
343 }
344}
345
347 SCOPED_TIME_STAT(&stats_);
348 CHECK(col_perm_.empty());
349 if (is_identity_factorization_) return;
350
351 // If non-zeros is non-empty, we use an hypersparse solve. Note that if
352 // non_zeros starts to be too big, we clear it and thus switch back to a
353 // normal sparse solve.
354 upper_.ComputeRowsToConsiderInSortedOrder(&x->non_zeros);
355 x->non_zeros_are_sorted = true;
356 if (x->non_zeros.empty()) {
357 transpose_upper_.TransposeLowerSolve(&x->values);
358 } else {
359 transpose_upper_.TransposeHyperSparseSolveWithReversedNonZeros(
360 &x->values, &x->non_zeros);
361 }
362}
363
365 ScatteredRow* y, ScatteredColumn* result_before_permutation) const {
366 SCOPED_TIME_STAT(&stats_);
367 if (is_identity_factorization_) {
368 // It is not advantageous to fill result_before_permutation in this case.
369 return false;
370 }
371 DenseColumn* const x = reinterpret_cast<DenseColumn*>(&y->values);
372 std::vector<RowIndex>* nz = reinterpret_cast<RowIndexVector*>(&y->non_zeros);
373
374 // Hypersparse?
375 transpose_lower_.ComputeRowsToConsiderInSortedOrder(nz);
376 y->non_zeros_are_sorted = true;
377 if (nz->empty()) {
378 lower_.TransposeLowerSolve(x);
379 } else {
380 lower_.TransposeHyperSparseSolveWithReversedNonZeros(x, nz);
381 }
382
383 if (result_before_permutation == nullptr) {
384 // Note(user): For the behavior of the two functions to be exactly the same,
385 // we need the positions listed in nz to be the "exact" non-zeros of x. This
386 // should be the case because the hyper-sparse functions makes sure of that.
387 // We also DCHECK() this below.
388 if (nz->empty()) {
389 PermuteWithScratchpad(inverse_row_perm_, &dense_zero_scratchpad_, x);
390 } else {
391 PermuteWithKnownNonZeros(inverse_row_perm_, &dense_zero_scratchpad_, x,
392 nz);
393 }
394 if (DEBUG_MODE) {
395 for (const RowIndex row : *nz) {
396 DCHECK_NE((*x)[row], 0.0);
397 }
398 }
399 return false;
400 }
401
402 // This computes the same thing as in the other branch but also keeps the
403 // original x in result_before_permutation. Because of this, it is faster to
404 // use a different algorithm.
405 ClearAndResizeVectorWithNonZeros(x->size(), result_before_permutation);
406 x->swap(result_before_permutation->values);
407 const auto input = result_before_permutation->values.const_view();
408 const auto inverse_row_perm = inverse_row_perm_.const_view();
409 if (nz->empty()) {
410 const RowIndex num_rows = inverse_row_perm.size();
411 for (RowIndex row(0); row < num_rows; ++row) {
412 const Fractional value = input[row];
413 if (value != 0.0) {
414 const RowIndex permuted_row = inverse_row_perm[row];
415 (*x)[permuted_row] = value;
416 }
417 }
418 } else {
419 nz->swap(result_before_permutation->non_zeros);
420 nz->reserve(result_before_permutation->non_zeros.size());
421 for (const RowIndex row : result_before_permutation->non_zeros) {
422 const Fractional value = input[row];
423 const RowIndex permuted_row = inverse_row_perm[row];
424 (*x)[permuted_row] = value;
425 nz->push_back(permuted_row);
426 }
427 y->non_zeros_are_sorted = false;
428 }
429 return true;
430}
431
435
437 ScatteredRow* y) const {
438 SCOPED_TIME_STAT(&stats_);
439 DCHECK(IsAllZero(y->values));
440 DCHECK(y->non_zeros.empty());
441 if (is_identity_factorization_) {
442 (*y)[col] = 1.0;
443 y->non_zeros.push_back(col);
444 return col;
445 }
446 const ColIndex permuted_col = col_perm_.empty() ? col : col_perm_[col];
447 (*y)[permuted_col] = 1.0;
448 y->non_zeros.push_back(permuted_col);
449
450 // Using the transposed matrix here is faster (even accounting the time to
451 // construct it). Note the small optimization in case the inversion is
452 // trivial.
453 if (transpose_upper_.ColumnIsDiagonalOnly(permuted_col)) {
454 (*y)[permuted_col] /= transpose_upper_.GetDiagonalCoefficient(permuted_col);
455 } else {
456 RowIndexVector* const nz = reinterpret_cast<RowIndexVector*>(&y->non_zeros);
457 DenseColumn* const x = reinterpret_cast<DenseColumn*>(&y->values);
458 transpose_upper_.ComputeRowsToConsiderInSortedOrder(nz);
459 y->non_zeros_are_sorted = true;
460 if (y->non_zeros.empty()) {
461 transpose_upper_.LowerSolveStartingAt(permuted_col, x);
462 } else {
463 transpose_upper_.HyperSparseSolve(x, nz);
464 }
465 }
466 return permuted_col;
467}
468
469const SparseColumn& LuFactorization::GetColumnOfU(ColIndex col) const {
470 if (is_identity_factorization_) {
471 column_of_upper_.Clear();
472 column_of_upper_.SetCoefficient(ColToRowIndex(col), 1.0);
473 return column_of_upper_;
474 }
475 upper_.CopyColumnToSparseColumn(col_perm_.empty() ? col : col_perm_[col],
476 &column_of_upper_);
477 return column_of_upper_;
478}
479
481 const CompactSparseMatrixView& matrix) const {
482 const int initial_num_entries = matrix.num_entries().value();
483 const int lu_num_entries =
484 (lower_.num_entries() + upper_.num_entries()).value();
485 if (is_identity_factorization_ || initial_num_entries == 0) return 1.0;
486 return static_cast<double>(lu_num_entries) /
487 static_cast<double>(initial_num_entries);
488}
489
491 return is_identity_factorization_
492 ? EntryIndex(0)
493 : lower_.num_entries() + upper_.num_entries();
494}
495
497 if (is_identity_factorization_) return 1.0;
498 DCHECK_EQ(upper_.num_rows().value(), upper_.num_cols().value());
499 Fractional product(1.0);
500 for (ColIndex col(0); col < upper_.num_cols(); ++col) {
501 product *= upper_.GetDiagonalCoefficient(col);
502 }
503 return product * row_perm_.ComputeSignature() *
504 inverse_col_perm_.ComputeSignature();
505}
506
508 if (is_identity_factorization_) return 1.0;
509 const RowIndex num_rows = lower_.num_rows();
510 const ColIndex num_cols = lower_.num_cols();
511 Fractional norm = 0.0;
512 for (ColIndex col(0); col < num_cols; ++col) {
513 DenseColumn right_hand_side(num_rows, 0.0);
514 right_hand_side[ColToRowIndex(col)] = 1.0;
515 // Get a column of the matrix inverse.
516 RightSolve(&right_hand_side);
517 Fractional column_norm = 0.0;
518 // Compute sum_i |basis_matrix_ij|.
519 for (RowIndex row(0); row < num_rows; ++row) {
520 column_norm += std::abs(right_hand_side[row]);
521 }
522 // Compute max_j sum_i |basis_matrix_ij|
523 norm = std::max(norm, column_norm);
524 }
525 return norm;
526}
527
529 if (is_identity_factorization_) return 1.0;
530 const RowIndex num_rows = lower_.num_rows();
531 const ColIndex num_cols = lower_.num_cols();
532 DenseColumn row_sum(num_rows, 0.0);
533 for (ColIndex col(0); col < num_cols; ++col) {
534 DenseColumn right_hand_side(num_rows, 0.0);
535 right_hand_side[ColToRowIndex(col)] = 1.0;
536 // Get a column of the matrix inverse.
537 RightSolve(&right_hand_side);
538 // Compute sum_j |basis_matrix_ij|.
539 for (RowIndex row(0); row < num_rows; ++row) {
540 row_sum[row] += std::abs(right_hand_side[row]);
541 }
542 }
543 // Compute max_i sum_j |basis_matrix_ij|
544 Fractional norm = 0.0;
545 for (RowIndex row(0); row < num_rows; ++row) {
546 norm = std::max(norm, row_sum[row]);
547 }
548 return norm;
549}
550
552 const CompactSparseMatrixView& matrix) const {
553 if (is_identity_factorization_) return 1.0;
554 return matrix.ComputeOneNorm() * ComputeInverseOneNorm();
555}
556
558 const CompactSparseMatrixView& matrix) const {
559 if (is_identity_factorization_) return 1.0;
561}
562
564 return lower_.ComputeInverseInfinityNormUpperBound() *
565 upper_.ComputeInverseInfinityNormUpperBound();
566}
567
568namespace {
569// Returns the density of the sparse column 'b' w.r.t. the given permutation.
570double ComputeDensity(const SparseColumn& b, const RowPermutation& row_perm) {
571 double density = 0.0;
572 for (const SparseColumn::Entry e : b) {
573 if (row_perm[e.row()] != kNonPivotal && e.coefficient() != 0.0) {
574 ++density;
575 }
576 }
577 const RowIndex num_rows = row_perm.size();
578 return density / num_rows.value();
579}
580} // anonymous namespace
581
582void LuFactorization::ComputeTransposeUpper() {
583 SCOPED_TIME_STAT(&stats_);
584 transpose_upper_.PopulateFromTranspose(upper_);
585}
586
587void LuFactorization::ComputeTransposeLower() const {
588 SCOPED_TIME_STAT(&stats_);
589 transpose_lower_.PopulateFromTranspose(lower_);
590}
591
592bool LuFactorization::CheckFactorization(const CompactSparseMatrixView& matrix,
593 Fractional tolerance) const {
594 if (is_identity_factorization_) return true;
595 SparseMatrix lu;
597 SparseMatrix paq;
598 paq.PopulateFromPermutedMatrix(matrix, row_perm_, inverse_col_perm_);
599 if (!row_perm_.Check()) {
600 return false;
601 }
602 if (!inverse_col_perm_.Check()) {
603 return false;
604 }
605
606 SparseMatrix should_be_zero;
607 should_be_zero.PopulateFromLinearCombination(Fractional(1.0), paq,
608 Fractional(-1.0), lu);
609
610 for (ColIndex col(0); col < should_be_zero.num_cols(); ++col) {
611 for (const SparseColumn::Entry e : should_be_zero.column(col)) {
612 const Fractional magnitude = std::abs(e.coefficient());
613 if (magnitude > tolerance) {
614 VLOG(2) << magnitude << " != 0, at column " << col;
615 return false;
616 }
617 }
618 }
619 return true;
620}
621
622} // namespace glop
623} // namespace operations_research
void RightSolveLForColumnView(const ColumnView &b, ScatteredColumn *x) const
void RightSolveUWithNonZeros(ScatteredColumn *x) const
ColIndex LeftSolveUForUnitRow(ColIndex col, ScatteredRow *y) const
double DeterministicTimeOfLastFactorization() const
Returns the deterministic time of the last factorization.
void RightSolveLForScatteredColumn(const ScatteredColumn &b, ScatteredColumn *x) const
void RightSolveLWithPermutedInput(const DenseColumn &a, ScatteredColumn *x) const
Fractional DualEdgeSquaredNorm(RowIndex row) const
Returns the norm of (B^T)^{-1}.e_row where e is an unit vector.
ABSL_MUST_USE_RESULT Status ComputeFactorization(const CompactSparseMatrixView &compact_matrix)
void RightSolveLWithNonZeros(ScatteredColumn *x) const
bool LeftSolveLWithNonZeros(ScatteredRow *y, ScatteredColumn *result_before_permutation) const
Fractional ComputeInfinityNormConditionNumber(const CompactSparseMatrixView &matrix) const
Fractional RightSolveSquaredNorm(const ColumnView &a) const
Returns the norm of B^{-1}.a.
RowToColMapping ComputeInitialBasis(const CompactSparseMatrix &matrix, const std::vector< ColIndex > &candidates)
Fractional ComputeOneNormConditionNumber(const CompactSparseMatrixView &matrix) const
double GetFillInPercentage(const CompactSparseMatrixView &matrix) const
void ComputeLowerTimesUpper(SparseMatrix *product) const
const SparseColumn & GetColumnOfU(ColIndex col) const
void LeftSolveUWithNonZeros(ScatteredRow *y) const
static Status OK()
Improves readability but identical to 0-arg constructor.
Definition status.h:55
@ ERROR_LU
The LU factorization of the current basis couldn't be computed.
Definition status.h:34
void LowerSolveStartingAt(ColIndex start, DenseColumn *rhs) const
This assumes that the rhs is all zero before the given position.
Definition sparse.cc:801
void ComputeRowsToConsiderInSortedOrder(RowIndexVector *non_zero_rows) const
Definition sparse.cc:1465
Fractional GetDiagonalCoefficient(ColIndex col) const
Returns the diagonal coefficient of the given column.
Definition sparse.h:675
bool ColumnIsDiagonalOnly(ColIndex col) const
Returns true iff the column contains no non-diagonal entries.
Definition sparse.h:680
void push_back(const value_type &val)
const bool DEBUG_MODE
Definition macros.h:26
constexpr ColIndex kInvalidCol(-1)
void PermuteWithScratchpad(const Permutation< PermutationIndexType > &permutation, StrictITIVector< IndexType, Fractional > *zero_scratchpad, StrictITIVector< IndexType, Fractional > *input_output)
Permutes the given dense vector. It uses for this an all zero scratchpad.
Definition lp_utils.h:244
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Definition lp_types.h:394
std::vector< RowIndex > RowIndexVector
Definition lp_types.h:361
Fractional Square(Fractional f)
Definition lp_utils.h:41
bool IsAllZero(const Container &input)
Returns true if the given Fractional container is all zeros.
Definition lp_utils.h:229
Permutation< RowIndex > RowPermutation
void PermuteWithKnownNonZeros(const Permutation< IndexType > &permutation, StrictITIVector< IndexType, Fractional > *zero_scratchpad, StrictITIVector< IndexType, Fractional > *output, std::vector< IndexType > *non_zeros)
Definition lp_utils.h:271
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
Definition lp_types.h:54
constexpr RowIndex kInvalidRow(-1)
void ClearAndResizeVectorWithNonZeros(IndexType size, ScatteredRowOrCol *v)
Sets a dense vector for which the non zeros are known to be non_zeros.
Definition lp_utils.h:290
RowIndex ColToRowIndex(ColIndex col)
Get the RowIndex corresponding to the row # col.
Definition lp_types.h:57
const RowIndex kNonPivotal(-1)
Fractional SquaredNorm(const SparseColumn &v)
Definition lp_utils.cc:36
void ApplyPermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
StrictITIVector< RowIndex, Fractional > DenseColumn
Column-vector types. Column-vector types are indexed by a row index.
Definition lp_types.h:380
StrictITIVector< ColIndex, Fractional > DenseRow
Row-vector types. Row-vector types are indexed by a column index.
Definition lp_types.h:351
Fractional SquaredNormAndResetToZero(absl::Span< Fractional > data)
Definition lp_utils.cc:103
void ApplyInversePermutation(const Permutation< IndexType > &perm, const ITIVectorType &b, ITIVectorType *result)
In SWIG mode, we don't want anything besides these top-level includes.
static int input(yyscan_t yyscanner)
#define IF_STATS_ENABLED(instructions)
Definition stats.h:417
#define SCOPED_TIME_STAT(stats)
Definition stats.h:418
#define GLOP_RETURN_IF_ERROR(function_call)
Macro to simplify error propagation between function returning Status.
Definition status.h:71
#define GLOP_RETURN_AND_LOG_ERROR(error_code, message)
Macro to simplify the creation of an error.
Definition status.h:78
StrictITIVector< Index, Fractional > values