Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
basis_representation.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 <cstdlib>
18#include <vector>
19
21#include "ortools/glop/status.h"
23
24namespace operations_research {
25namespace glop {
26
27// --------------------------------------------------------
28// EtaMatrix
29// --------------------------------------------------------
30
31const Fractional EtaMatrix::kSparseThreshold = 0.5;
32
33EtaMatrix::EtaMatrix(ColIndex eta_col, const ScatteredColumn& direction)
34 : eta_col_(eta_col),
35 eta_col_coefficient_(direction[ColToRowIndex(eta_col)]),
36 eta_coeff_(),
37 sparse_eta_coeff_() {
38 DCHECK_NE(0.0, eta_col_coefficient_);
39 eta_coeff_ = direction.values;
40 eta_coeff_[ColToRowIndex(eta_col_)] = 0.0;
41
42 // Only fill sparse_eta_coeff_ if it is sparse enough.
43 if (direction.non_zeros.size() <
44 kSparseThreshold * eta_coeff_.size().value()) {
45 for (const RowIndex row : direction.non_zeros) {
46 if (row == ColToRowIndex(eta_col)) continue;
47 sparse_eta_coeff_.SetCoefficient(row, eta_coeff_[row]);
48 }
49 DCHECK(sparse_eta_coeff_.CheckNoDuplicates());
50 }
51}
52
53EtaMatrix::~EtaMatrix() = default;
54
55void EtaMatrix::LeftSolve(DenseRow* y) const {
57 DCHECK_EQ(RowToColIndex(eta_coeff_.size()), y->size());
58 if (!sparse_eta_coeff_.IsEmpty()) {
59 LeftSolveWithSparseEta(y);
60 } else {
61 LeftSolveWithDenseEta(y);
62 }
63}
64
65void EtaMatrix::RightSolve(DenseColumn* d) const {
67 DCHECK_EQ(eta_coeff_.size(), d->size());
68
69 // Nothing to do if 'a' is zero at position eta_row.
70 // This exploits the possible sparsity of the column 'a'.
71 if ((*d)[ColToRowIndex(eta_col_)] == 0.0) return;
72 if (!sparse_eta_coeff_.IsEmpty()) {
73 RightSolveWithSparseEta(d);
74 } else {
75 RightSolveWithDenseEta(d);
76 }
77}
78
79void EtaMatrix::SparseLeftSolve(DenseRow* y, ColIndexVector* pos) const {
81 DCHECK_EQ(RowToColIndex(eta_coeff_.size()), y->size());
82
83 Fractional y_value = (*y)[eta_col_];
84 bool is_eta_col_in_pos = false;
85 const int size = pos->size();
86 for (int i = 0; i < size; ++i) {
87 const ColIndex col = (*pos)[i];
88 const RowIndex row = ColToRowIndex(col);
89 if (col == eta_col_) {
90 is_eta_col_in_pos = true;
91 continue;
92 }
93 y_value -= (*y)[col] * eta_coeff_[row];
94 }
95
96 (*y)[eta_col_] = y_value / eta_col_coefficient_;
97
98 // We add the new non-zero position if it wasn't already there.
99 if (!is_eta_col_in_pos) pos->push_back(eta_col_);
100}
101
102void EtaMatrix::LeftSolveWithDenseEta(DenseRow* y) const {
103 Fractional y_value = (*y)[eta_col_];
104 const RowIndex num_rows(eta_coeff_.size());
105 for (RowIndex row(0); row < num_rows; ++row) {
106 y_value -= (*y)[RowToColIndex(row)] * eta_coeff_[row];
107 }
108 (*y)[eta_col_] = y_value / eta_col_coefficient_;
109}
110
111void EtaMatrix::LeftSolveWithSparseEta(DenseRow* y) const {
112 Fractional y_value = (*y)[eta_col_];
113 for (const SparseColumn::Entry e : sparse_eta_coeff_) {
114 y_value -= (*y)[RowToColIndex(e.row())] * e.coefficient();
115 }
116 (*y)[eta_col_] = y_value / eta_col_coefficient_;
117}
118
119void EtaMatrix::RightSolveWithDenseEta(DenseColumn* d) const {
120 const RowIndex eta_row = ColToRowIndex(eta_col_);
121 const Fractional coeff = (*d)[eta_row] / eta_col_coefficient_;
122 const RowIndex num_rows(eta_coeff_.size());
123 for (RowIndex row(0); row < num_rows; ++row) {
124 (*d)[row] -= eta_coeff_[row] * coeff;
125 }
126 (*d)[eta_row] = coeff;
127}
128
129void EtaMatrix::RightSolveWithSparseEta(DenseColumn* d) const {
130 const RowIndex eta_row = ColToRowIndex(eta_col_);
131 const Fractional coeff = (*d)[eta_row] / eta_col_coefficient_;
132 for (const SparseColumn::Entry e : sparse_eta_coeff_) {
133 (*d)[e.row()] -= e.coefficient() * coeff;
134 }
135 (*d)[eta_row] = coeff;
136}
137
138// --------------------------------------------------------
139// EtaFactorization
140// --------------------------------------------------------
141EtaFactorization::EtaFactorization() : eta_matrix_() {}
142
144
146
147void EtaFactorization::Update(ColIndex entering_col,
148 RowIndex leaving_variable_row,
149 const ScatteredColumn& direction) {
150 const ColIndex leaving_variable_col = RowToColIndex(leaving_variable_row);
151 EtaMatrix* const eta_factorization =
152 new EtaMatrix(leaving_variable_col, direction);
153 eta_matrix_.push_back(eta_factorization);
154}
155
158 for (int i = eta_matrix_.size() - 1; i >= 0; --i) {
159 eta_matrix_[i]->LeftSolve(y);
161}
162
165 for (int i = eta_matrix_.size() - 1; i >= 0; --i) {
166 eta_matrix_[i]->SparseLeftSolve(y, pos);
168}
169
172 const size_t num_eta_matrices = eta_matrix_.size();
173 for (int i = 0; i < num_eta_matrices; ++i) {
174 eta_matrix_[i]->RightSolve(d);
175 }
176}
177
178// --------------------------------------------------------
179// BasisFactorization
180// --------------------------------------------------------
182 const CompactSparseMatrix* compact_matrix, const RowToColMapping* basis)
183 : stats_(),
184 compact_matrix_(*compact_matrix),
185 basis_(*basis),
186 tau_is_computed_(false),
187 max_num_updates_(0),
188 num_updates_(0),
189 eta_factorization_(),
190 lu_factorization_(),
191 deterministic_time_(0.0) {
192 SetParameters(parameters_);
193}
194
196
198 SCOPED_TIME_STAT(&stats_);
199 num_updates_ = 0;
200 tau_computation_can_be_optimized_ = false;
201 eta_factorization_.Clear();
202 lu_factorization_.Clear();
203 rank_one_factorization_.Clear();
204 storage_.Reset(compact_matrix_.num_rows());
205 right_storage_.Reset(compact_matrix_.num_rows());
206 left_pool_mapping_.clear();
207 right_pool_mapping_.clear();
208}
209
211 SCOPED_TIME_STAT(&stats_);
212 Clear();
213 if (IsIdentityBasis()) return Status::OK();
214 return ComputeFactorization();
215}
218 const std::vector<ColIndex>& candidates) {
219 const RowToColMapping basis =
220 lu_factorization_.ComputeInitialBasis(compact_matrix_, candidates);
221 deterministic_time_ +=
222 lu_factorization_.DeterministicTimeOfLastFactorization();
223 return basis;
224}
225
226bool BasisFactorization::IsRefactorized() const { return num_updates_ == 0; }
227
229 if (IsRefactorized()) return Status::OK();
230 return ForceRefactorization();
231}
235 stats_.refactorization_interval.Add(num_updates_);
236 Clear();
237 return ComputeFactorization();
238}
240Status BasisFactorization::ComputeFactorization() {
241 CompactSparseMatrixView basis_matrix(&compact_matrix_, &basis_);
242 const Status status = lu_factorization_.ComputeFactorization(basis_matrix);
243 last_factorization_deterministic_time_ =
244 lu_factorization_.DeterministicTimeOfLastFactorization();
245 deterministic_time_ += last_factorization_deterministic_time_;
246 rank_one_factorization_.ResetDeterministicTime();
247 return status;
248}
249
250// This update formula can be derived by:
251// e = unit vector on the leaving_variable_row
252// new B = L.U + (matrix.column(entering_col) - B.e).e^T
253// new B = L.U + L.L^{-1}.(matrix.column(entering_col) - B.e).e^T.U^{-1}.U
254// new B = L.(Identity +
255// (right_update_vector - U.column(leaving_column)).left_update_vector).U
256// new B = L.RankOneUpdateElementatyMatrix(
257// right_update_vector - U.column(leaving_column), left_update_vector)
258Status BasisFactorization::MiddleProductFormUpdate(
259 ColIndex entering_col, RowIndex leaving_variable_row) {
260 const ColIndex right_index = entering_col < right_pool_mapping_.size()
261 ? right_pool_mapping_[entering_col]
262 : kInvalidCol;
263 const ColIndex left_index =
264 RowToColIndex(leaving_variable_row) < left_pool_mapping_.size()
265 ? left_pool_mapping_[RowToColIndex(leaving_variable_row)]
266 : kInvalidCol;
267 if (right_index == kInvalidCol || left_index == kInvalidCol) {
268 LOG(INFO) << "One update vector is missing!!!";
269 return ForceRefactorization();
270 }
271
272 // TODO(user): create a class for these operations.
273 // Initialize scratchpad_ with the right update vector.
274 DCHECK(IsAllZero(scratchpad_));
275 scratchpad_.resize(right_storage_.num_rows(), 0.0);
276 const auto view = right_storage_.view();
277 for (const EntryIndex i : view.Column(right_index)) {
278 const RowIndex row = view.EntryRow(i);
279 scratchpad_[row] = view.EntryCoefficient(i);
280 scratchpad_non_zeros_.push_back(row);
281 }
282 // Subtract the column of U from scratchpad_.
283 const SparseColumn& column_of_u =
284 lu_factorization_.GetColumnOfU(RowToColIndex(leaving_variable_row));
285 for (const SparseColumn::Entry e : column_of_u) {
286 scratchpad_[e.row()] -= e.coefficient();
287 scratchpad_non_zeros_.push_back(e.row());
288 }
289
290 // Creates the new rank one update matrix and update the factorization.
291 const Fractional scalar_product =
292 storage_.ColumnScalarProduct(left_index, Transpose(scratchpad_));
293 const ColIndex u_index = storage_.AddAndClearColumnWithNonZeros(
294 &scratchpad_, &scratchpad_non_zeros_);
295 RankOneUpdateElementaryMatrix elementary_update_matrix(
296 &storage_, u_index, left_index, scalar_product);
297 if (elementary_update_matrix.IsSingular()) {
298 GLOP_RETURN_AND_LOG_ERROR(Status::ERROR_LU, "Degenerate rank-one update.");
299 }
300 rank_one_factorization_.Update(elementary_update_matrix);
301 return Status::OK();
302}
303
304Status BasisFactorization::Update(ColIndex entering_col,
305 RowIndex leaving_variable_row,
306 const ScatteredColumn& direction) {
307 // Note that in addition to the logic here, we also refactorize when we detect
308 // numerical imprecisions. There is various tests for that during an
309 // iteration.
310 if (num_updates_ >= max_num_updates_) {
311 if (!parameters_.dynamically_adjust_refactorization_period()) {
312 return ForceRefactorization();
313 }
314
315 // We try to equilibrate the factorization time with the EXTRA solve time
316 // incurred since the last factorization.
317 //
318 // Note(user): The deterministic time is not really super precise for now.
319 // We tend to undercount the factorization, but this tends to favorize more
320 // refactorization which is good for numerical stability.
321 if (last_factorization_deterministic_time_ <
322 rank_one_factorization_.DeterministicTimeSinceLastReset()) {
323 return ForceRefactorization();
324 }
325 }
326
327 // Note(user): in some rare case (to investigate!) MiddleProductFormUpdate()
328 // will trigger a full refactorization. Because of this, it is important to
329 // increment num_updates_ first as this counter is used by IsRefactorized().
330 SCOPED_TIME_STAT(&stats_);
331 ++num_updates_;
332 if (use_middle_product_form_update_) {
334 MiddleProductFormUpdate(entering_col, leaving_variable_row));
335 } else {
336 eta_factorization_.Update(entering_col, leaving_variable_row, direction);
337 }
338 tau_computation_can_be_optimized_ = false;
339 return Status::OK();
340}
341
342void BasisFactorization::LeftSolve(ScatteredRow* y) const {
343 SCOPED_TIME_STAT(&stats_);
345 if (use_middle_product_form_update_) {
346 lu_factorization_.LeftSolveUWithNonZeros(y);
347 rank_one_factorization_.LeftSolveWithNonZeros(y);
348 lu_factorization_.LeftSolveLWithNonZeros(y);
349 y->SortNonZerosIfNeeded();
350 } else {
351 y->non_zeros.clear();
352 eta_factorization_.LeftSolve(&y->values);
353 lu_factorization_.LeftSolve(&y->values);
354 }
355 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
356}
357
358void BasisFactorization::RightSolve(ScatteredColumn* d) const {
359 SCOPED_TIME_STAT(&stats_);
361 if (use_middle_product_form_update_) {
362 lu_factorization_.RightSolveLWithNonZeros(d);
363 rank_one_factorization_.RightSolveWithNonZeros(d);
364 lu_factorization_.RightSolveUWithNonZeros(d);
365 d->SortNonZerosIfNeeded();
366 } else {
367 d->non_zeros.clear();
368 lu_factorization_.RightSolve(&d->values);
369 eta_factorization_.RightSolve(&d->values);
370 }
371 BumpDeterministicTimeForSolve(d->NumNonZerosEstimate());
372}
373
375 const ScatteredColumn& a) const {
376 SCOPED_TIME_STAT(&stats_);
377 if (use_middle_product_form_update_) {
378 if (tau_computation_can_be_optimized_) {
379 // Once used, the intermediate result is overwritten, so
380 // RightSolveForTau() can no longer use the optimized algorithm.
381 tau_computation_can_be_optimized_ = false;
382 lu_factorization_.RightSolveLWithPermutedInput(a.values, &tau_);
383 } else {
384 ClearAndResizeVectorWithNonZeros(compact_matrix_.num_rows(), &tau_);
385 lu_factorization_.RightSolveLForScatteredColumn(a, &tau_);
386 }
387 rank_one_factorization_.RightSolveWithNonZeros(&tau_);
388 lu_factorization_.RightSolveUWithNonZeros(&tau_);
389 } else {
390 tau_.non_zeros.clear();
391 tau_.values = a.values;
392 lu_factorization_.RightSolve(&tau_.values);
393 eta_factorization_.RightSolve(&tau_.values);
394 }
395 tau_is_computed_ = true;
396 BumpDeterministicTimeForSolve(tau_.NumNonZerosEstimate());
397 return tau_.values;
398}
399
401 ScatteredRow* y) const {
402 SCOPED_TIME_STAT(&stats_);
405 y);
406 if (!use_middle_product_form_update_) {
407 (*y)[j] = 1.0;
408 y->non_zeros.push_back(j);
409 eta_factorization_.SparseLeftSolve(&y->values, &y->non_zeros);
410 lu_factorization_.LeftSolve(&y->values);
411 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
412 return;
413 }
414
415 // If the leaving index is the same, we can reuse the column! Note also that
416 // since we do a left solve for a unit row using an upper triangular matrix,
417 // all positions in front of the unit will be zero (modulo the column
418 // permutation).
419 if (j >= left_pool_mapping_.size()) {
420 left_pool_mapping_.resize(j + 1, kInvalidCol);
421 }
422 if (left_pool_mapping_[j] == kInvalidCol) {
423 const ColIndex start = lu_factorization_.LeftSolveUForUnitRow(j, y);
424 if (y->non_zeros.empty()) {
425 left_pool_mapping_[j] = storage_.AddDenseColumnPrefix(
427 } else {
428 left_pool_mapping_[j] = storage_.AddDenseColumnWithNonZeros(
429 Transpose(y->values),
430 *reinterpret_cast<RowIndexVector*>(&y->non_zeros));
431 }
432 } else {
433 DenseColumn* const x = reinterpret_cast<DenseColumn*>(y);
434 RowIndexVector* const nz = reinterpret_cast<RowIndexVector*>(&y->non_zeros);
435 storage_.ColumnCopyToClearedDenseColumnWithNonZeros(left_pool_mapping_[j],
436 x, nz);
437 }
438
439 rank_one_factorization_.LeftSolveWithNonZeros(y);
440
441 // We only keep the intermediate result needed for the optimized tau_
442 // computation if it was computed after the last time this was called.
443 if (tau_is_computed_) {
444 tau_computation_can_be_optimized_ =
445 lu_factorization_.LeftSolveLWithNonZeros(y, &tau_);
446 } else {
447 tau_computation_can_be_optimized_ = false;
448 lu_factorization_.LeftSolveLWithNonZeros(y);
449 }
450 tau_is_computed_ = false;
451 y->SortNonZerosIfNeeded();
452 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
453}
454
456 ScatteredRow* y) const {
457 CHECK(IsRefactorized());
458 SCOPED_TIME_STAT(&stats_);
462 lu_factorization_.LeftSolveUForUnitRow(j, y);
463 lu_factorization_.LeftSolveLWithNonZeros(y);
464 y->SortNonZerosIfNeeded();
465 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
466}
467
469 ScatteredColumn* d) const {
470 SCOPED_TIME_STAT(&stats_);
472 ClearAndResizeVectorWithNonZeros(compact_matrix_.num_rows(), d);
473
474 if (!use_middle_product_form_update_) {
475 compact_matrix_.ColumnCopyToClearedDenseColumn(col, &d->values);
476 lu_factorization_.RightSolve(&d->values);
477 eta_factorization_.RightSolve(&d->values);
478 BumpDeterministicTimeForSolve(d->NumNonZerosEstimate());
479 return;
480 }
481
482 // TODO(user): if right_pool_mapping_[col] != kInvalidCol, we can reuse it and
483 // just apply the last rank one update since it was computed.
484 lu_factorization_.RightSolveLForColumnView(compact_matrix_.column(col), d);
485 rank_one_factorization_.RightSolveWithNonZeros(d);
486 if (col >= right_pool_mapping_.size()) {
487 right_pool_mapping_.resize(col + 1, kInvalidCol);
488 }
489 if (d->non_zeros.empty()) {
490 right_pool_mapping_[col] = right_storage_.AddDenseColumn(d->values);
491 } else {
492 // The sort is needed if we want to have the same behavior for the sparse or
493 // hyper-sparse version.
494 std::sort(d->non_zeros.begin(), d->non_zeros.end());
495 right_pool_mapping_[col] =
496 right_storage_.AddDenseColumnWithNonZeros(d->values, d->non_zeros);
497 }
498 lu_factorization_.RightSolveUWithNonZeros(d);
500 BumpDeterministicTimeForSolve(d->NumNonZerosEstimate());
501}
502
504 const ColumnView& a) const {
505 SCOPED_TIME_STAT(&stats_);
506 DCHECK(IsRefactorized());
507 BumpDeterministicTimeForSolve(a.num_entries().value());
508 return lu_factorization_.RightSolveSquaredNorm(a);
510
512 SCOPED_TIME_STAT(&stats_);
513 DCHECK(IsRefactorized());
514 BumpDeterministicTimeForSolve(1);
515 return lu_factorization_.DualEdgeSquaredNorm(row);
516}
518bool BasisFactorization::IsIdentityBasis() const {
519 const RowIndex num_rows = compact_matrix_.num_rows();
520 for (RowIndex row(0); row < num_rows; ++row) {
521 const ColIndex col = basis_[row];
522 if (compact_matrix_.column(col).num_entries().value() != 1) return false;
523 const Fractional coeff = compact_matrix_.column(col).GetFirstCoefficient();
524 const RowIndex entry_row = compact_matrix_.column(col).GetFirstRow();
525 if (entry_row != row || coeff != 1.0) return false;
526 }
527 return true;
528}
529
531 if (IsIdentityBasis()) return 1.0;
532 CompactSparseMatrixView basis_matrix(&compact_matrix_, &basis_);
533 return basis_matrix.ComputeOneNorm();
534}
535
537 if (IsIdentityBasis()) return 1.0;
538 CompactSparseMatrixView basis_matrix(&compact_matrix_, &basis_);
539 return basis_matrix.ComputeInfinityNorm();
540}
541
542// TODO(user): try to merge the computation of the norm of inverses
543// with that of MatrixView. Maybe use a wrapper class for InverseMatrix.
544
546 if (IsIdentityBasis()) return 1.0;
547 const RowIndex num_rows = compact_matrix_.num_rows();
548 const ColIndex num_cols = RowToColIndex(num_rows);
549 Fractional norm = 0.0;
550 for (ColIndex col(0); col < num_cols; ++col) {
551 ScatteredColumn right_hand_side;
552 right_hand_side.values.AssignToZero(num_rows);
553 right_hand_side[ColToRowIndex(col)] = 1.0;
554 // Get a column of the matrix inverse.
555 RightSolve(&right_hand_side);
556 Fractional column_norm = 0.0;
557 // Compute sum_i |inverse_ij|.
558 for (RowIndex row(0); row < num_rows; ++row) {
559 column_norm += std::abs(right_hand_side[row]);
560 }
561 // Compute max_j sum_i |inverse_ij|
562 norm = std::max(norm, column_norm);
563 }
564 return norm;
565}
566
568 if (IsIdentityBasis()) return 1.0;
569 const RowIndex num_rows = compact_matrix_.num_rows();
570 const ColIndex num_cols = RowToColIndex(num_rows);
571 DenseColumn row_sum(num_rows, 0.0);
572 for (ColIndex col(0); col < num_cols; ++col) {
573 ScatteredColumn right_hand_side;
574 right_hand_side.values.AssignToZero(num_rows);
575 right_hand_side[ColToRowIndex(col)] = 1.0;
576 // Get a column of the matrix inverse.
577 RightSolve(&right_hand_side);
578 // Compute sum_j |inverse_ij|.
579 for (RowIndex row(0); row < num_rows; ++row) {
580 row_sum[row] += std::abs(right_hand_side[row]);
581 }
582 }
583 // Compute max_i sum_j |inverse_ij|
584 Fractional norm = 0.0;
585 for (RowIndex row(0); row < num_rows; ++row) {
586 norm = std::max(norm, row_sum[row]);
587 }
588 return norm;
589}
590
592 if (IsIdentityBasis()) return 1.0;
594}
595
597 if (IsIdentityBasis()) return 1.0;
599}
600
602 const {
603 if (IsIdentityBasis()) return 1.0;
604 BumpDeterministicTimeForSolve(compact_matrix_.num_rows().value());
605 return ComputeInfinityNorm() *
606 lu_factorization_.ComputeInverseInfinityNormUpperBound();
608
610 return deterministic_time_;
611}
612
613void BasisFactorization::BumpDeterministicTimeForSolve(int num_entries) const {
614 // TODO(user): Spend more time finding a good approximation here.
615 if (compact_matrix_.num_rows().value() == 0) return;
616 const double density =
617 static_cast<double>(num_entries) /
618 static_cast<double>(compact_matrix_.num_rows().value());
619 deterministic_time_ +=
621 lu_factorization_.NumberOfEntries().value()) +
623 rank_one_factorization_.num_entries().value());
624}
625
626} // namespace glop
627} // namespace operations_research
IntegerValue y
IntegerValue size
Fractional ComputeInverseInfinityNorm() const
Computes the infinity-norm of the inverse of B.
ABSL_MUST_USE_RESULT Status Update(ColIndex entering_col, RowIndex leaving_variable_row, const ScatteredColumn &direction)
const DenseColumn & RightSolveForTau(const ScatteredColumn &a) const
void RightSolve(ScatteredColumn *d) const
Right solves the system B.d = a where the input is the initial value of d.
void LeftSolveForUnitRow(ColIndex j, ScatteredRow *y) const
RowToColMapping ComputeInitialBasis(const std::vector< ColIndex > &candidates)
void TemporaryLeftSolveForUnitRow(ColIndex j, ScatteredRow *y) const
Same as LeftSolveForUnitRow() but does not update any internal data.
bool IsRefactorized() const
Returns true if the factorization was just recomputed.
BasisFactorization(const CompactSparseMatrix *compact_matrix, const RowToColMapping *basis)
Fractional RightSolveSquaredNorm(const ColumnView &a) const
void RightSolveForProblemColumn(ColIndex col, ScatteredColumn *d) const
void LeftSolve(ScatteredRow *y) const
Left solves the system y.B = rhs, where y initially contains rhs.
ColIndex AddDenseColumnPrefix(DenseColumn::ConstView dense_column, RowIndex start)
Same as AddDenseColumn(), but only adds the non-zero from the given start.
Definition sparse.cc:582
ColIndex AddDenseColumn(const DenseColumn &dense_column)
Definition sparse.cc:578
ColIndex AddAndClearColumnWithNonZeros(DenseColumn *column, std::vector< RowIndex > *non_zeros)
Definition sparse.cc:611
void ColumnCopyToClearedDenseColumnWithNonZeros(ColIndex col, DenseColumn *dense_column, RowIndexVector *non_zeros) const
Same as ColumnCopyToClearedDenseColumn() but also fills non_zeros.
Definition sparse.h:493
ColIndex AddDenseColumnWithNonZeros(const DenseColumn &dense_column, const std::vector< RowIndex > &non_zeros)
Definition sparse.cc:596
void ColumnCopyToClearedDenseColumn(ColIndex col, DenseColumn *dense_column) const
Definition sparse.h:481
Fractional ColumnScalarProduct(ColIndex col, const DenseRow &vector) const
Definition sparse.h:434
ColumnView column(ColIndex col) const
Definition sparse.h:416
void RightSolve(DenseColumn *d) const
Right solves all systems from left to right, i.e. E_i.d_{i+1} = d_i.
void SparseLeftSolve(DenseRow *y, ColIndexVector *pos) const
void LeftSolve(DenseRow *y) const
Left solves all systems from right to left, i.e. y_i = y_{i+1}.(E_i)^{-1}.
void Update(ColIndex entering_col, RowIndex leaving_variable_row, const ScatteredColumn &direction)
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 RightSolveSquaredNorm(const ColumnView &a) const
Returns the norm of B^{-1}.a.
RowToColMapping ComputeInitialBasis(const CompactSparseMatrix &matrix, const std::vector< ColIndex > &candidates)
const SparseColumn & GetColumnOfU(ColIndex col) const
void LeftSolveUWithNonZeros(ScatteredRow *y) const
void Clear()
Deletes all elementary matrices of this factorization.
void Update(const RankOneUpdateElementaryMatrix &update_matrix)
Updates the factorization.
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
int64_t a
Definition table.cc:44
absl::Status status
Definition g_gurobi.cc:44
ColIndex col
Definition markowitz.cc:187
RowIndex row
Definition markowitz.cc:186
void STLDeleteElements(T *container)
Definition stl_util.h:372
constexpr ColIndex kInvalidCol(-1)
StrictITIVector< RowIndex, ColIndex > RowToColMapping
Definition lp_types.h:396
std::vector< RowIndex > RowIndexVector
Definition lp_types.h:363
std::vector< ColIndex > ColIndexVector
Vector of row or column indices. Useful to list the non-zero positions.
Definition lp_types.h:362
bool IsAllZero(const Container &input)
Returns true if the given Fractional container is all zeros.
Definition lp_utils.h:229
const DenseRow & Transpose(const DenseColumn &col)
Similar comment as the other Transpose() implementation above.
Definition lp_utils.h:199
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
Definition lp_types.h:54
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
StrictITIVector< RowIndex, Fractional > DenseColumn
Column-vector types. Column-vector types are indexed by a row index.
Definition lp_types.h:382
StrictITIVector< ColIndex, Fractional > DenseRow
Row-vector types. Row-vector types are indexed by a column index.
Definition lp_types.h:353
static double DeterministicTimeForFpOperations(int64_t n)
Definition lp_types.h:435
In SWIG mode, we don't want anything besides these top-level includes.
util_intops::StrongVector< ColumnEntryIndex, ElementIndex, ElementAllocator > SparseColumn
const Variable x
Definition qp_tests.cc:127
#define RETURN_IF_NULL(x)
int64_t start
#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