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()) {
45 for (
const RowIndex row : direction.
non_zeros) {
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) {
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();
214 return ComputeFactorization();
218 const std::vector<ColIndex>& candidates) {
220 lu_factorization_.ComputeInitialBasis(compact_matrix_, candidates);
221 deterministic_time_ +=
222 lu_factorization_.DeterministicTimeOfLastFactorization();
235 stats_.refactorization_interval.Add(num_updates_);
237 return ComputeFactorization();
240Status BasisFactorization::ComputeFactorization() {
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();
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());
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()) {
300 rank_one_factorization_.Update(elementary_update_matrix);
305 RowIndex leaving_variable_row,
310 if (num_updates_ >= max_num_updates_) {
311 if (!parameters_.dynamically_adjust_refactorization_period()) {
321 if (last_factorization_deterministic_time_ <
322 rank_one_factorization_.DeterministicTimeSinceLastReset()) {
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_) {
346 lu_factorization_.LeftSolveUWithNonZeros(y);
347 rank_one_factorization_.LeftSolveWithNonZeros(y);
348 lu_factorization_.LeftSolveLWithNonZeros(y);
349 y->SortNonZerosIfNeeded();
351 y->non_zeros.clear();
352 eta_factorization_.
LeftSolve(&y->values);
355 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
361 if (use_middle_product_form_update_) {
364 lu_factorization_.RightSolveUWithNonZeros(d);
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;
382 lu_factorization_.RightSolveLWithPermutedInput(a.values, &tau_);
395 tau_is_computed_ =
true;
396 BumpDeterministicTimeForSolve(tau_.NumNonZerosEstimate());
406 if (!use_middle_product_form_update_) {
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());
419 if (j >= left_pool_mapping_.
size()) {
424 if (y->non_zeros.empty()) {
435 storage_.ColumnCopyToClearedDenseColumnWithNonZeros(left_pool_mapping_[j],
439 rank_one_factorization_.LeftSolveWithNonZeros(y);
443 if (tau_is_computed_) {
444 tau_computation_can_be_optimized_ =
445 lu_factorization_.LeftSolveLWithNonZeros(y, &tau_);
447 tau_computation_can_be_optimized_ =
false;
448 lu_factorization_.LeftSolveLWithNonZeros(y);
450 tau_is_computed_ =
false;
451 y->SortNonZerosIfNeeded();
452 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
462 lu_factorization_.LeftSolveUForUnitRow(j, y);
463 lu_factorization_.LeftSolveLWithNonZeros(y);
464 y->SortNonZerosIfNeeded();
465 BumpDeterministicTimeForSolve(y->NumNonZerosEstimate());
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);
486 if (col >= right_pool_mapping_.
size()) {
495 right_pool_mapping_[col] =
498 lu_factorization_.RightSolveUWithNonZeros(d);
507 BumpDeterministicTimeForSolve(a.num_entries().value());
508 return lu_factorization_.RightSolveSquaredNorm(a);
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];
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;
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());
606 lu_factorization_.ComputeInverseInfinityNormUpperBound();
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_ +=
621 lu_factorization_.NumberOfEntries().value()) +
623 rank_one_factorization_.num_entries().value());