29#ifndef OR_TOOLS_LP_DATA_SPARSE_H_
30#define OR_TOOLS_LP_DATA_SPARSE_H_
37#include "absl/log/check.h"
38#include "absl/types/span.h"
51class CompactSparseMatrixView;
77#if (!defined(_MSC_VER) || _MSC_VER >= 1800)
79 std::initializer_list<std::initializer_list<Fractional>> init_list);
133 template <
typename Matrix>
142 template <
typename Matrix>
188 RowIndex
num_rows()
const {
return num_rows_; }
189 ColIndex
num_cols()
const {
return ColIndex(columns_.size()); }
210 std::string
Dump()
const;
237 const ColIndex
num_cols = matrix.num_cols();
240 columns_[
col] = &matrix.column(
col);
242 num_rows_ = matrix.num_rows();
248 const SparseMatrix& matrix_b) {
249 const ColIndex
num_cols = matrix_a.num_cols() + matrix_b.num_cols();
251 for (ColIndex
col(0);
col < matrix_a.num_cols(); ++
col) {
252 columns_[
col] = &matrix_a.column(
col);
254 for (ColIndex
col(0);
col < matrix_b.num_cols(); ++
col) {
255 columns_[matrix_a.num_cols() +
col] = &matrix_b.column(
col);
257 num_rows_ = std::max(matrix_a.num_rows(), matrix_b.num_rows());
264 for (RowIndex
row(0);
row < basis.size(); ++
row) {
267 num_rows_ = matrix.num_rows();
271 bool IsEmpty()
const {
return columns_.empty(); }
272 RowIndex
num_rows()
const {
return num_rows_; }
273 ColIndex
num_cols()
const {
return columns_.size(); }
306 : coefficients_(matrix->coefficients_.data()),
307 rows_(matrix->rows_.data()),
308 starts_(matrix->starts_.data()) {}
317 return ::util::IntegerRange<EntryIndex>(starts_[
col.value()],
318 starts_[
col.value() + 1]);
320 Fractional EntryCoefficient(EntryIndex i)
const {
321 return coefficients_[i.value()];
323 RowIndex EntryRow(EntryIndex i)
const {
return rows_[i.value()]; }
325 EntryIndex ColumnNumEntries(ColIndex
col)
const {
326 return starts_[
col.value() + 1] - starts_[
col.value()];
336 const RowIndex*
const rows_;
337 const EntryIndex*
const starts_;
341 ConstView view()
const {
return ConstView(
this); }
370 void Reset(RowIndex num_rows);
375 ColIndex AddDenseColumn(
const DenseColumn& dense_column);
383 ColIndex AddDenseColumnWithNonZeros(
const DenseColumn& dense_column,
384 const std::vector<RowIndex>& non_zeros);
391 std::vector<RowIndex>* non_zeros);
394 EntryIndex ColumnNumEntries(ColIndex
col)
const {
395 return starts_[
col + 1] - starts_[
col];
399 EntryIndex num_entries()
const {
400 DCHECK_EQ(coefficients_.size(), rows_.size());
401 return coefficients_.size();
403 RowIndex num_rows()
const {
return num_rows_; }
404 ColIndex num_cols()
const {
return num_cols_; }
407 bool IsEmpty()
const {
408 DCHECK_EQ(coefficients_.size(), rows_.size());
409 return coefficients_.empty();
415 DCHECK_LT(
col, num_cols_);
419 const EntryIndex
start = starts_[
col];
421 coefficients_.data() +
start.value());
426 bool ColumnIsEmpty(ColIndex
col)
const {
427 return starts_[
col + 1] == starts_[
col];
439 void ColumnAddMultipleToDenseColumn(ColIndex
col,
Fractional multiplier,
441 if (multiplier == 0.0)
return;
442 const auto entry_rows = rows_.view();
443 const auto entry_coeffs = coefficients_.view();
444 for (
const EntryIndex i : Column(
col)) {
445 dense_column[entry_rows[i]] += multiplier * entry_coeffs[i];
448 void ColumnAddMultipleToDenseColumn(ColIndex
col,
Fractional multiplier,
451 dense_column->view());
457 void ColumnAddMultipleToSparseScatteredColumn(ColIndex
col,
461 if (multiplier == 0.0)
return;
462 const auto entry_rows = rows_.view();
463 const auto entry_coeffs = coefficients_.view();
464 for (
const EntryIndex i : Column(
col)) {
465 column->Add(entry_rows[i], multiplier * entry_coeffs[i]);
471 void ColumnCopyToDenseColumn(ColIndex
col,
DenseColumn* dense_column)
const {
474 ColumnCopyToClearedDenseColumn(
col, dense_column);
479 void ColumnCopyToClearedDenseColumn(ColIndex
col,
482 dense_column->
resize(num_rows_, 0.0);
483 const auto entry_rows = rows_.view();
484 const auto entry_coeffs = coefficients_.view();
485 for (
const EntryIndex i : Column(
col)) {
486 (*dense_column)[entry_rows[i]] = entry_coeffs[i];
491 void ColumnCopyToClearedDenseColumnWithNonZeros(
495 dense_column->resize(num_rows_, 0.0);
497 const auto entry_rows = rows_.view();
498 const auto entry_coeffs = coefficients_.view();
499 for (
const EntryIndex i : Column(
col)) {
500 const RowIndex
row = entry_rows[i];
501 (*dense_column)[
row] = entry_coeffs[i];
502 non_zeros->push_back(
row);
511 return ::util::IntegerRange<EntryIndex>(starts_[
col], starts_[
col + 1]);
530 int i = starts_[
col.value()].value();
531 const int end = starts_[
col.value() + 1].value();
532 const int shifted_end =
end - 3;
537 for (; i < shifted_end; i += 4) {
538 result1 += coefficients_[i] * vector[
RowToColIndex(rows_[i])];
539 result2 += coefficients_[i + 1] * vector[
RowToColIndex(rows_[i + 1])];
540 result3 += coefficients_[i + 2] * vector[
RowToColIndex(rows_[i + 2])];
541 result4 += coefficients_[i + 3] * vector[
RowToColIndex(rows_[i + 3])];
543 Fractional result = result1 + result2 + result3 + result4;
545 result += coefficients_[i] * vector[
RowToColIndex(rows_[i])];
547 result += coefficients_[i + 1] * vector[
RowToColIndex(rows_[i + 1])];
549 result += coefficients_[i + 2] * vector[
RowToColIndex(rows_[i + 2])];
560class CompactSparseMatrixView {
564 : compact_matrix_(*compact_matrix),
565 columns_(basis->data(), basis->
size().
value()) {}
567 const std::vector<ColIndex>* columns)
568 : compact_matrix_(*compact_matrix), columns_(*columns) {}
571 bool IsEmpty()
const {
return compact_matrix_.IsEmpty(); }
572 RowIndex
num_rows()
const {
return compact_matrix_.num_rows(); }
573 ColIndex
num_cols()
const {
return ColIndex(columns_.size()); }
575 return compact_matrix_.column(columns_[
col.value()]);
585 const absl::Span<const ColIndex> columns_;
608 bool IsEmpty()
const {
return diagonal_coefficients_.empty(); }
640 RowIndex diagonal_row,
642 void AddDiagonalOnlyColumn(
Fractional diagonal_value);
649 RowIndex diagonal_row,
653 void ApplyRowPermutationToNonDiagonalEntries(
const RowPermutation& row_perm);
656 void CopyColumnToSparseColumn(ColIndex
col,
SparseColumn* output)
const;
664 ColIndex GetFirstNonIdentityColumn()
const {
665 return first_non_identity_column_;
670 return diagonal_coefficients_[
col];
674 bool ColumnIsDiagonalOnly(ColIndex
col)
const {
733 void HyperSparseSolveWithReversedNonZeros(
737 void TransposeHyperSparseSolveWithReversedNonZeros(
745 void ComputeRowsToConsiderWithDfs(
RowIndexVector* non_zero_rows)
const;
751 void ComputeRowsToConsiderInSortedOrder(
RowIndexVector* non_zero_rows)
const;
790 void PermutedLowerSparseSolve(
const ColumnView& rhs,
795 int64_t NumFpOperationsInLastPermutedLowerSparseSolve()
const {
796 return num_fp_operations_;
803 bool IsLowerTriangular()
const;
804 bool IsUpperTriangular()
const;
821 void PermutedComputeRowsToConsider(
const ColumnView& rhs,
829 Fractional ComputeInverseInfinityNormUpperBound()
const;
830 Fractional ComputeInverseInfinityNorm()
const;
834 template <
bool diagonal_of_ones>
835 void LowerSolveStartingAtInternal(ColIndex
start,
837 template <
bool diagonal_of_ones>
839 template <
bool diagonal_of_ones>
841 template <
bool diagonal_of_ones>
843 template <
bool diagonal_of_ones>
846 template <
bool diagonal_of_ones>
847 void HyperSparseSolveWithReversedNonZerosInternal(
849 template <
bool diagonal_of_ones>
852 template <
bool diagonal_of_ones>
853 void TransposeHyperSparseSolveWithReversedNonZerosInternal(
858 void CloseCurrentColumn(
Fractional diagonal_value);
866 ColIndex first_non_identity_column_;
870 bool all_diagonal_coefficients_are_one_;
875 mutable std::vector<RowIndex> nodes_to_explore_;
878 int64_t num_fp_operations_;
879 mutable std::vector<RowIndex> lower_column_rows_;
880 mutable std::vector<RowIndex> upper_column_rows_;
881 mutable DenseColumn initially_all_zero_scratchpad_;
Fractional ColumnScalarProduct(ColIndex col, DenseRow::ConstView vector) const
void Reset(RowIndex num_rows)
CompactSparseMatrix & operator=(const CompactSparseMatrix &)=delete
CompactSparseMatrix()=default
StrictITIVector< EntryIndex, Fractional > coefficients_
void ColumnAddMultipleToDenseColumn(ColIndex col, Fractional multiplier, DenseColumn *dense_column) const
EntryIndex num_entries() const
Returns the matrix dimensions. See same functions in SparseMatrix.
RowIndex num_rows() const
bool IsEmpty() const
Returns whether or not this matrix contains any non-zero entries.
ColIndex num_cols() const
bool ColumnIsEmpty(ColIndex col) const
void Swap(CompactSparseMatrix *other)
void PopulateFromTranspose(const CompactSparseMatrix &input)
RowIndex num_rows_
The matrix dimensions, properly updated by full and incremental builders.
RowIndex num_rows() const
void PopulateFromMatrixPair(const SparseMatrix &matrix_a, const SparseMatrix &matrix_b)
Fractional ComputeInfinityNorm() const
ColIndex num_cols() const
void PopulateFromMatrix(const SparseMatrix &matrix)
Takes all the columns of the given matrix.
bool IsEmpty() const
Same behavior as the SparseMatrix functions above.
EntryIndex num_entries() const
Fractional ComputeOneNorm() const
void PopulateFromBasis(const MatrixView &matrix, const RowToColMapping &basis)
Takes only the columns of the given matrix that belongs to the given basis.
void ComputeMinAndMaxMagnitudes(Fractional *min_magnitude, Fractional *max_magnitude) const
void PopulateFromProduct(const SparseMatrix &a, const SparseMatrix &b)
Multiplies SparseMatrix a by SparseMatrix b.
std::string Dump() const
Returns a dense representation of the matrix.
void PopulateFromPermutedMatrix(const Matrix &a, const RowPermutation &row_perm, const ColumnPermutation &inverse_col_perm)
SparseMatrix & operator=(const SparseMatrix &)=delete
void PopulateFromTranspose(const Matrix &input)
Instantiate needed templates.
bool CheckNoDuplicates() const
Call CheckNoDuplicates() on all columns, useful for doing a DCHECK.
void PopulateFromLinearCombination(Fractional alpha, const SparseMatrix &a, Fractional beta, const SparseMatrix &b)
SparseColumn * mutable_column(ColIndex col)
void AppendUnitVector(RowIndex row, Fractional value)
void Swap(SparseMatrix *matrix)
bool IsCleanedUp() const
Call IsCleanedUp() on all columns, useful for doing a DCHECK.
void ApplyRowPermutation(const RowPermutation &row_perm)
Applies the row permutation.
void DeleteRows(RowIndex num_rows, const RowPermutation &permutation)
void PopulateFromIdentity(ColIndex num_cols)
RowIndex num_rows() const
Return the matrix dimension.
Fractional ComputeInfinityNorm() const
void PopulateFromZero(RowIndex num_rows, ColIndex num_cols)
bool AppendRowsFromSparseMatrix(const SparseMatrix &matrix)
void DeleteColumns(const DenseBooleanRow &columns_to_delete)
Fractional ComputeOneNorm() const
void PopulateFromSparseMatrix(const SparseMatrix &matrix)
bool Equals(const SparseMatrix &a, Fractional tolerance) const
ColIndex num_cols() const
ColIndex AppendEmptyColumn()
Appends an empty column and returns its index.
void SetNumRows(RowIndex num_rows)
Change the number of row of this matrix.
EntryIndex num_entries() const
Fractional LookUpValue(RowIndex row, ColIndex col) const
StrictITISpan< RowIndex, Fractional > View
void AssignToZero(IntType size)
StrictITISpan< RowIndex, const Fractional > ConstView
ConstView const_view() const
void resize(IntType size)
StrictITIVector< RowIndex, ColIndex > RowToColMapping
std::vector< RowIndex > RowIndexVector
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
StrictITIVector< RowIndex, Fractional > DenseColumn
Column-vector types. Column-vector types are indexed by a row index.
In SWIG mode, we don't want anything besides these top-level includes.
static int input(yyscan_t yyscanner)
#define RETURN_IF_NULL(x)
std::optional< int64_t > end