Google OR-Tools v9.11
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-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 <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
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 const std::vector<RowIndex>& non_zeros, absl::Span<Fractional> column) {
137 Fractional sum = 0.0;
138 if (non_zeros.empty()) {
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 {
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;
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 {
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 {
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 if (nz->empty()) {
408 for (RowIndex row(0); row < inverse_row_perm_.size(); ++row) {
409 const Fractional value = (*result_before_permutation)[row];
410 if (value != 0.0) {
411 const RowIndex permuted_row = inverse_row_perm_[row];
412 (*x)[permuted_row] = value;
413 }
414 }
415 } else {
416 nz->swap(result_before_permutation->non_zeros);
417 nz->reserve(result_before_permutation->non_zeros.size());
418 for (const RowIndex row : result_before_permutation->non_zeros) {
419 const Fractional value = (*result_before_permutation)[row];
420 const RowIndex permuted_row = inverse_row_perm_[row];
421 (*x)[permuted_row] = value;
422 nz->push_back(permuted_row);
423 }
424 y->non_zeros_are_sorted = false;
425 }
426 return true;
427}
428
432
434 ScatteredRow* y) const {
435 SCOPED_TIME_STAT(&stats_);
436 DCHECK(IsAllZero(y->values));
437 DCHECK(y->non_zeros.empty());
438 if (is_identity_factorization_) {
439 (*y)[col] = 1.0;
440 y->non_zeros.push_back(col);
441 return col;
442 }
443 const ColIndex permuted_col = col_perm_.empty() ? col : col_perm_[col];
444 (*y)[permuted_col] = 1.0;
445 y->non_zeros.push_back(permuted_col);
446
447 // Using the transposed matrix here is faster (even accounting the time to
448 // construct it). Note the small optimization in case the inversion is
449 // trivial.
450 if (transpose_upper_.ColumnIsDiagonalOnly(permuted_col)) {
451 (*y)[permuted_col] /= transpose_upper_.GetDiagonalCoefficient(permuted_col);
452 } else {
453 RowIndexVector* const nz = reinterpret_cast<RowIndexVector*>(&y->non_zeros);
454 DenseColumn* const x = reinterpret_cast<DenseColumn*>(&y->values);
455 transpose_upper_.ComputeRowsToConsiderInSortedOrder(nz);
456 y->non_zeros_are_sorted = true;
457 if (y->non_zeros.empty()) {
458 transpose_upper_.LowerSolveStartingAt(permuted_col, x);
459 } else {
460 transpose_upper_.HyperSparseSolve(x, nz);
461 }
462 }
463 return permuted_col;
464}
465
467 if (is_identity_factorization_) {
468 column_of_upper_.Clear();
469 column_of_upper_.SetCoefficient(ColToRowIndex(col), 1.0);
470 return column_of_upper_;
471 }
472 upper_.CopyColumnToSparseColumn(col_perm_.empty() ? col : col_perm_[col],
473 &column_of_upper_);
474 return column_of_upper_;
475}
476
478 const CompactSparseMatrixView& matrix) const {
479 const int initial_num_entries = matrix.num_entries().value();
480 const int lu_num_entries =
481 (lower_.num_entries() + upper_.num_entries()).value();
482 if (is_identity_factorization_ || initial_num_entries == 0) return 1.0;
483 return static_cast<double>(lu_num_entries) /
484 static_cast<double>(initial_num_entries);
485}
486
488 return is_identity_factorization_
489 ? EntryIndex(0)
490 : lower_.num_entries() + upper_.num_entries();
491}
492
494 if (is_identity_factorization_) return 1.0;
495 DCHECK_EQ(upper_.num_rows().value(), upper_.num_cols().value());
496 Fractional product(1.0);
497 for (ColIndex col(0); col < upper_.num_cols(); ++col) {
498 product *= upper_.GetDiagonalCoefficient(col);
499 }
500 return product * row_perm_.ComputeSignature() *
501 inverse_col_perm_.ComputeSignature();
502}
503
505 if (is_identity_factorization_) return 1.0;
506 const RowIndex num_rows = lower_.num_rows();
507 const ColIndex num_cols = lower_.num_cols();
508 Fractional norm = 0.0;
509 for (ColIndex col(0); col < num_cols; ++col) {
510 DenseColumn right_hand_side(num_rows, 0.0);
511 right_hand_side[ColToRowIndex(col)] = 1.0;
512 // Get a column of the matrix inverse.
513 RightSolve(&right_hand_side);
514 Fractional column_norm = 0.0;
515 // Compute sum_i |basis_matrix_ij|.
516 for (RowIndex row(0); row < num_rows; ++row) {
517 column_norm += std::abs(right_hand_side[row]);
518 }
519 // Compute max_j sum_i |basis_matrix_ij|
520 norm = std::max(norm, column_norm);
521 }
522 return norm;
523}
524
526 if (is_identity_factorization_) return 1.0;
527 const RowIndex num_rows = lower_.num_rows();
528 const ColIndex num_cols = lower_.num_cols();
529 DenseColumn row_sum(num_rows, 0.0);
530 for (ColIndex col(0); col < num_cols; ++col) {
531 DenseColumn right_hand_side(num_rows, 0.0);
532 right_hand_side[ColToRowIndex(col)] = 1.0;
533 // Get a column of the matrix inverse.
534 RightSolve(&right_hand_side);
535 // Compute sum_j |basis_matrix_ij|.
536 for (RowIndex row(0); row < num_rows; ++row) {
537 row_sum[row] += std::abs(right_hand_side[row]);
538 }
539 }
540 // Compute max_i sum_j |basis_matrix_ij|
541 Fractional norm = 0.0;
542 for (RowIndex row(0); row < num_rows; ++row) {
543 norm = std::max(norm, row_sum[row]);
544 }
545 return norm;
546}
547
549 const CompactSparseMatrixView& matrix) const {
550 if (is_identity_factorization_) return 1.0;
551 return matrix.ComputeOneNorm() * ComputeInverseOneNorm();
552}
553
555 const CompactSparseMatrixView& matrix) const {
556 if (is_identity_factorization_) return 1.0;
558}
559
564
565namespace {
566// Returns the density of the sparse column 'b' w.r.t. the given permutation.
567double ComputeDensity(const SparseColumn& b, const RowPermutation& row_perm) {
568 double density = 0.0;
569 for (const SparseColumn::Entry e : b) {
570 if (row_perm[e.row()] != kNonPivotal && e.coefficient() != 0.0) {
571 ++density;
572 }
573 }
574 const RowIndex num_rows = row_perm.size();
575 return density / num_rows.value();
576}
577} // anonymous namespace
578
579void LuFactorization::ComputeTransposeUpper() {
580 SCOPED_TIME_STAT(&stats_);
581 transpose_upper_.PopulateFromTranspose(upper_);
582}
583
584void LuFactorization::ComputeTransposeLower() const {
585 SCOPED_TIME_STAT(&stats_);
586 transpose_lower_.PopulateFromTranspose(lower_);
587}
588
589bool LuFactorization::CheckFactorization(const CompactSparseMatrixView& matrix,
590 Fractional tolerance) const {
591 if (is_identity_factorization_) return true;
592 SparseMatrix lu;
594 SparseMatrix paq;
595 paq.PopulateFromPermutedMatrix(matrix, row_perm_, inverse_col_perm_);
596 if (!row_perm_.Check()) {
597 return false;
598 }
599 if (!inverse_col_perm_.Check()) {
600 return false;
601 }
602
603 SparseMatrix should_be_zero;
604 should_be_zero.PopulateFromLinearCombination(Fractional(1.0), paq,
605 Fractional(-1.0), lu);
606
607 for (ColIndex col(0); col < should_be_zero.num_cols(); ++col) {
608 for (const SparseColumn::Entry e : should_be_zero.column(col)) {
609 const Fractional magnitude = std::abs(e.coefficient());
610 if (magnitude > tolerance) {
611 VLOG(2) << magnitude << " != 0, at column " << col;
612 return false;
613 }
614 }
615 }
616 return true;
617}
618
619} // namespace glop
620} // namespace operations_research
IntegerValue y
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
ABSL_MUST_USE_RESULT Status ComputeRowAndColumnPermutation(const CompactSparseMatrixView &basis_matrix, RowPermutation *row_perm, ColumnPermutation *col_perm)
Definition markowitz.cc:31
double DeterministicTimeOfLastFactorization() const
Returns an estimate of the time spent in the last factorization.
Definition markowitz.cc:557
ABSL_MUST_USE_RESULT Status ComputeLU(const CompactSparseMatrixView &basis_matrix, RowPermutation *row_perm, ColumnPermutation *col_perm, TriangularMatrix *lower, TriangularMatrix *upper)
Definition markowitz.cc:153
void PopulateFromInverse(const Permutation &inverse)
bool Check() const
Returns true if the calling object contains a permutation, false otherwise.
void Clear()
Clears the vector, i.e. removes all entries.
void SetCoefficient(Index index, Fractional value)
Defines the coefficient at index, i.e. vector[index] = value;.
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 UpperSolve(DenseColumn *rhs) const
Solves the system U.x = rhs for an upper triangular matrix.
Definition sparse.cc:817
void PopulateFromTranspose(const TriangularMatrix &input)
Definition sparse.cc:533
void Reset(RowIndex num_rows, ColIndex col_capacity)
Definition sparse.cc:566
void LowerSolve(DenseColumn *rhs) const
Definition sparse.cc:781
void LowerSolveStartingAt(ColIndex start, DenseColumn *rhs) const
This assumes that the rhs is all zero before the given position.
Definition sparse.cc:785
Fractional ComputeInverseInfinityNormUpperBound() const
Definition sparse.cc:1493
void HyperSparseSolveWithReversedNonZeros(DenseColumn *rhs, RowIndexVector *non_zero_rows) const
Definition sparse.cc:992
void TransposeHyperSparseSolve(DenseColumn *rhs, RowIndexVector *non_zero_rows) const
Definition sparse.cc:1027
void ComputeRowsToConsiderInSortedOrder(RowIndexVector *non_zero_rows) const
Definition sparse.cc:1448
void CopyColumnToSparseColumn(ColIndex col, SparseColumn *output) const
Copy a triangular column with its diagonal entry to the given SparseColumn.
Definition sparse.cc:762
Fractional GetDiagonalCoefficient(ColIndex col) const
Returns the diagonal coefficient of the given column.
Definition sparse.h:671
bool ColumnIsDiagonalOnly(ColIndex col) const
Returns true iff the column contains no non-diagonal entries.
Definition sparse.h:676
void TransposeHyperSparseSolveWithReversedNonZeros(DenseColumn *rhs, RowIndexVector *non_zero_rows) const
Definition sparse.cc:1079
void TransposeUpperSolve(DenseColumn *rhs) const
Definition sparse.cc:851
void HyperSparseSolve(DenseColumn *rhs, RowIndexVector *non_zero_rows) const
Definition sparse.cc:960
void TransposeLowerSolve(DenseColumn *rhs) const
Definition sparse.cc:902
value_type * data()
– Pass-through methods to STL vector ----------------------------------—
void push_back(const value_type &val)
int64_t b
Definition table.cc:45
int64_t a
Definition table.cc:44
int64_t value
const bool DEBUG_MODE
Definition macros.h:24
ColIndex col
Definition markowitz.cc:187
RowIndex row
Definition markowitz.cc:186
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
std::vector< RowIndex > RowIndexVector
Definition lp_types.h:363
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
void PermuteWithKnownNonZeros(const Permutation< IndexType > &permutation, StrictITIVector< IndexType, Fractional > *zero_scratchpad, StrictITIVector< IndexType, Fractional > *output, std::vector< IndexType > *non_zeros)
Definition lp_utils.h:266
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:285
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)
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.
int column
const Variable x
Definition qp_tests.cc:127
#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