31const Fractional EtaMatrix::kSparseThreshold = 0.5;
38 DCHECK_NE(0.0, eta_col_coefficient_);
39 eta_coeff_ = direction.
values;
44 kSparseThreshold * eta_coeff_.size().value()) {
47 sparse_eta_coeff_.SetCoefficient(
row, eta_coeff_[
row]);
49 DCHECK(sparse_eta_coeff_.CheckNoDuplicates());
53EtaMatrix::~EtaMatrix() =
default;
55void EtaMatrix::LeftSolve(
DenseRow*
y)
const {
58 if (!sparse_eta_coeff_.IsEmpty()) {
59 LeftSolveWithSparseEta(
y);
61 LeftSolveWithDenseEta(
y);
67 DCHECK_EQ(eta_coeff_.size(), d->
size());
72 if (!sparse_eta_coeff_.IsEmpty()) {
73 RightSolveWithSparseEta(d);
75 RightSolveWithDenseEta(d);
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];
89 if (
col == eta_col_) {
90 is_eta_col_in_pos =
true;
93 y_value -= (*y)[
col] * eta_coeff_[
row];
96 (*y)[eta_col_] = y_value / eta_col_coefficient_;
99 if (!is_eta_col_in_pos) pos->push_back(eta_col_);
102void EtaMatrix::LeftSolveWithDenseEta(
DenseRow*
y)
const {
104 const RowIndex num_rows(eta_coeff_.size());
105 for (RowIndex
row(0);
row < num_rows; ++
row) {
108 (*y)[eta_col_] = y_value / eta_col_coefficient_;
111void EtaMatrix::LeftSolveWithSparseEta(
DenseRow*
y)
const {
113 for (
const SparseColumn::Entry e : sparse_eta_coeff_) {
116 (*y)[eta_col_] = y_value / eta_col_coefficient_;
119void EtaMatrix::RightSolveWithDenseEta(
DenseColumn* d)
const {
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;
126 (*d)[eta_row] = coeff;
129void EtaMatrix::RightSolveWithSparseEta(
DenseColumn* d)
const {
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;
135 (*d)[eta_row] = coeff;
148 RowIndex leaving_variable_row,
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);
158 for (
int i = eta_matrix_.size() - 1; i >= 0; --i) {
159 eta_matrix_[i]->LeftSolve(
y);
165 for (
int i = eta_matrix_.size() - 1; i >= 0; --i) {
166 eta_matrix_[i]->SparseLeftSolve(
y, pos);
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);
182 const CompactSparseMatrix* compact_matrix,
const RowToColMapping* basis)
184 compact_matrix_(*compact_matrix),
186 tau_is_computed_(false),
189 eta_factorization_(),
191 deterministic_time_(0.0) {
192 SetParameters(parameters_);
200 tau_computation_can_be_optimized_ =
false;
201 eta_factorization_.
Clear();
202 lu_factorization_.
Clear();
206 left_pool_mapping_.clear();
207 right_pool_mapping_.clear();
214 return ComputeFactorization();
218 const std::vector<ColIndex>& candidates) {
221 deterministic_time_ +=
235 stats_.refactorization_interval.
Add(num_updates_);
237 return ComputeFactorization();
240Status BasisFactorization::ComputeFactorization() {
243 last_factorization_deterministic_time_ =
245 deterministic_time_ += last_factorization_deterministic_time_;
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]
263 const ColIndex left_index =
268 LOG(INFO) <<
"One update vector is missing!!!";
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);
285 for (
const SparseColumn::Entry e : column_of_u) {
286 scratchpad_[e.row()] -= e.coefficient();
287 scratchpad_non_zeros_.push_back(e.row());
294 &scratchpad_, &scratchpad_non_zeros_);
295 RankOneUpdateElementaryMatrix elementary_update_matrix(
296 &storage_, u_index, left_index, scalar_product);
297 if (elementary_update_matrix.IsSingular()) {
300 rank_one_factorization_.
Update(elementary_update_matrix);
305 RowIndex leaving_variable_row,
306 const ScatteredColumn& direction) {
310 if (num_updates_ >= max_num_updates_) {
311 if (!parameters_.dynamically_adjust_refactorization_period()) {
321 if (last_factorization_deterministic_time_ <
332 if (use_middle_product_form_update_) {
334 MiddleProductFormUpdate(entering_col, leaving_variable_row));
336 eta_factorization_.
Update(entering_col, leaving_variable_row, direction);
338 tau_computation_can_be_optimized_ =
false;
345 if (use_middle_product_form_update_) {
349 y->SortNonZerosIfNeeded();
351 y->non_zeros.clear();
355 BumpDeterministicTimeForSolve(
y->NumNonZerosEstimate());
361 if (use_middle_product_form_update_) {
365 d->SortNonZerosIfNeeded();
367 d->non_zeros.clear();
371 BumpDeterministicTimeForSolve(d->NumNonZerosEstimate());
375 const ScatteredColumn&
a)
const {
377 if (use_middle_product_form_update_) {
378 if (tau_computation_can_be_optimized_) {
381 tau_computation_can_be_optimized_ =
false;
395 tau_is_computed_ =
true;
401 ScatteredRow*
y)
const {
406 if (!use_middle_product_form_update_) {
408 y->non_zeros.push_back(j);
411 BumpDeterministicTimeForSolve(
y->NumNonZerosEstimate());
419 if (j >= left_pool_mapping_.
size()) {
424 if (
y->non_zeros.empty()) {
443 if (tau_is_computed_) {
444 tau_computation_can_be_optimized_ =
447 tau_computation_can_be_optimized_ =
false;
450 tau_is_computed_ =
false;
451 y->SortNonZerosIfNeeded();
452 BumpDeterministicTimeForSolve(
y->NumNonZerosEstimate());
456 ScatteredRow*
y)
const {
464 y->SortNonZerosIfNeeded();
465 BumpDeterministicTimeForSolve(
y->NumNonZerosEstimate());
474 if (!use_middle_product_form_update_) {
486 if (
col >= right_pool_mapping_.
size()) {
495 right_pool_mapping_[
col] =
504 const ColumnView&
a)
const {
507 BumpDeterministicTimeForSolve(
a.num_entries().value());
514 BumpDeterministicTimeForSolve(1);
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];
525 if (entry_row !=
row || coeff != 1.0)
return false;
531 if (IsIdentityBasis())
return 1.0;
533 return basis_matrix.ComputeOneNorm();
537 if (IsIdentityBasis())
return 1.0;
546 if (IsIdentityBasis())
return 1.0;
547 const RowIndex num_rows = compact_matrix_.
num_rows();
550 for (ColIndex
col(0);
col < num_cols; ++
col) {
558 for (RowIndex
row(0);
row < num_rows; ++
row) {
559 column_norm += std::abs(right_hand_side[
row]);
562 norm = std::max(norm, column_norm);
568 if (IsIdentityBasis())
return 1.0;
569 const RowIndex num_rows = compact_matrix_.
num_rows();
572 for (ColIndex
col(0);
col < num_cols; ++
col) {
579 for (RowIndex
row(0);
row < num_rows; ++
row) {
580 row_sum[
row] += std::abs(right_hand_side[
row]);
585 for (RowIndex
row(0);
row < num_rows; ++
row) {
586 norm = std::max(norm, row_sum[
row]);
592 if (IsIdentityBasis())
return 1.0;
597 if (IsIdentityBasis())
return 1.0;
603 if (IsIdentityBasis())
return 1.0;
604 BumpDeterministicTimeForSolve(compact_matrix_.
num_rows().value());
610 return deterministic_time_;
613void BasisFactorization::BumpDeterministicTimeForSolve(
int num_entries)
const {
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_ +=
Fractional ComputeInfinityNorm() const
double DeterministicTime() const
Fractional ComputeInverseInfinityNorm() const
Computes the infinity-norm of the inverse of B.
Fractional ComputeOneNormConditionNumber() const
ABSL_MUST_USE_RESULT Status ForceRefactorization()
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.
ABSL_MUST_USE_RESULT Status Initialize()
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
Fractional ComputeInfinityNormConditionNumberUpperBound() const
void RightSolveForProblemColumn(ColIndex col, ScatteredColumn *d) const
Fractional ComputeOneNorm() const
ABSL_MUST_USE_RESULT Status Refactorize()
Fractional ComputeInfinityNormConditionNumber() const
void LeftSolve(ScatteredRow *y) const
Left solves the system y.B = rhs, where y initially contains rhs.
Fractional DualEdgeSquaredNorm(RowIndex row) const
virtual ~BasisFactorization()
Fractional ComputeInverseOneNorm() const
EntryIndex num_entries() const
RowIndex GetFirstRow() const
Fractional GetFirstCoefficient() const
Fractional ComputeInfinityNorm() const
void Reset(RowIndex num_rows)
ColIndex AddDenseColumnPrefix(DenseColumn::ConstView dense_column, RowIndex start)
Same as AddDenseColumn(), but only adds the non-zero from the given start.
ColIndex AddDenseColumn(const DenseColumn &dense_column)
ColIndex AddAndClearColumnWithNonZeros(DenseColumn *column, std::vector< RowIndex > *non_zeros)
RowIndex num_rows() const
void ColumnCopyToClearedDenseColumnWithNonZeros(ColIndex col, DenseColumn *dense_column, RowIndexVector *non_zeros) const
Same as ColumnCopyToClearedDenseColumn() but also fills non_zeros.
ColIndex AddDenseColumnWithNonZeros(const DenseColumn &dense_column, const std::vector< RowIndex > &non_zeros)
void ColumnCopyToClearedDenseColumn(ColIndex col, DenseColumn *dense_column) const
Fractional ColumnScalarProduct(ColIndex col, const DenseRow &vector) const
ColumnView column(ColIndex col) const
virtual ~EtaFactorization()
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 Clear()
Deletes all eta matrices.
void RightSolveLForColumnView(const ColumnView &b, ScatteredColumn *x) const
void RightSolve(DenseColumn *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 LeftSolve(DenseRow *y) const
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.
Fractional ComputeInverseInfinityNormUpperBound() const
ABSL_MUST_USE_RESULT Status ComputeFactorization(const CompactSparseMatrixView &compact_matrix)
EntryIndex NumberOfEntries() const
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 LeftSolveWithNonZeros(ScatteredRow *y) const
double DeterministicTimeSinceLastReset() const
void ResetDeterministicTime()
EntryIndex num_entries() const
void RightSolveWithNonZeros(ScatteredColumn *d) 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.
@ ERROR_LU
The LU factorization of the current basis couldn't be computed.
void AssignToZero(IntType size)
ConstView const_view() const
void resize(IntType size)
void STLDeleteElements(T *container)
constexpr ColIndex kInvalidCol(-1)
StrictITIVector< RowIndex, ColIndex > RowToColMapping
std::vector< RowIndex > RowIndexVector
std::vector< ColIndex > ColIndexVector
Vector of row or column indices. Useful to list the non-zero positions.
bool IsAllZero(const Container &input)
Returns true if the given Fractional container is all zeros.
const DenseRow & Transpose(const DenseColumn &col)
Similar comment as the other Transpose() implementation above.
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
void ClearAndResizeVectorWithNonZeros(IndexType size, ScatteredRowOrCol *v)
Sets a dense vector for which the non zeros are known to be non_zeros.
RowIndex ColToRowIndex(ColIndex col)
Get the RowIndex corresponding to the row # col.
StrictITIVector< RowIndex, Fractional > DenseColumn
Column-vector types. Column-vector types are indexed by a row index.
StrictITIVector< ColIndex, Fractional > DenseRow
Row-vector types. Row-vector types are indexed by a column index.
static double DeterministicTimeForFpOperations(int64_t n)
In SWIG mode, we don't want anything besides these top-level includes.
util_intops::StrongVector< ColumnEntryIndex, ElementIndex, ElementAllocator > SparseColumn
#define RETURN_IF_NULL(x)
#define SCOPED_TIME_STAT(stats)
#define GLOP_RETURN_IF_ERROR(function_call)
Macro to simplify error propagation between function returning Status.
#define GLOP_RETURN_AND_LOG_ERROR(error_code, message)
Macro to simplify the creation of an error.
void SortNonZerosIfNeeded()
StrictITIVector< Index, Fractional > values
std::vector< Index > non_zeros
size_t NumNonZerosEstimate() const