22#include "absl/log/check.h"
40 DCHECK(
a.IsCleanedUp());
41 DCHECK(
b.IsCleanedUp());
42 if (
a.num_entries() !=
b.num_entries())
return false;
44 bool a_is_larger =
true;
45 for (
const EntryIndex i :
a.AllEntryIndices()) {
46 if (
a.EntryRow(i) !=
b.EntryRow(i))
return false;
49 if (multiple == 0.0) {
50 a_is_larger = std::abs(coeff_a) > std::abs(coeff_b);
51 multiple = a_is_larger ? coeff_a / coeff_b : coeff_b / coeff_a;
54 if (std::abs(coeff_a / coeff_b - multiple) > tolerance)
return false;
56 if (std::abs(coeff_b / coeff_a - multiple) > tolerance)
return false;
64struct ColumnFingerprint {
65 ColumnFingerprint(ColIndex _col, int64_t _hash,
double _value)
75 bool operator<(
const ColumnFingerprint& other)
const {
76 if (
hash == other.hash) {
77 return value < other.value;
79 return hash < other.hash;
86bool AreProportionalCandidates(ColumnFingerprint
a, ColumnFingerprint
b,
88 if (
a.hash !=
b.hash)
return false;
89 return std::abs(
a.value -
b.value) < tolerance;
97 int64_t non_zero_pattern_hash = 0;
98 Fractional min_abs = std::numeric_limits<Fractional>::max();
101 for (
const SparseColumn::Entry e :
column) {
102 non_zero_pattern_hash =
104 sum += e.coefficient();
105 min_abs = std::min(min_abs, std::abs(e.coefficient()));
106 max_abs = std::max(max_abs, std::abs(e.coefficient()));
112 DCHECK_NE(0.0, max_abs);
113 const double inverse_dynamic_range = min_abs / max_abs;
114 const double scaled_average =
116 (
static_cast<double>(
column.num_entries().
value()) * max_abs);
117 return ColumnFingerprint(
col, non_zero_pattern_hash,
118 inverse_dynamic_range + scaled_average);
125 const ColIndex num_cols = matrix.
num_cols();
129 std::vector<ColumnFingerprint> fingerprints;
130 for (ColIndex
col(0);
col < num_cols; ++
col) {
132 fingerprints.push_back(ComputeFingerprint(
col, matrix.
column(
col)));
135 std::sort(fingerprints.begin(), fingerprints.end());
139 for (
int i = 0; i < fingerprints.size(); ++i) {
140 const ColIndex col_a = fingerprints[i].col;
142 for (
int j = i + 1; j < fingerprints.size(); ++j) {
143 const ColIndex col_b = fingerprints[j].col;
149 if (!AreProportionalCandidates(fingerprints[i], fingerprints[j],
153 if (AreColumnsProportional(matrix.
column(col_a), matrix.
column(col_b),
155 mapping[col_b] = col_a;
163 for (ColIndex
col(0);
col < num_cols; ++
col) {
165 const ColIndex new_representative = mapping[mapping[
col]];
167 mapping[
col] = new_representative;
170 mapping[mapping[
col]] =
col;
181 const ColIndex num_cols = matrix.
num_cols();
183 for (ColIndex col_a(0); col_a < num_cols; ++col_a) {
186 for (ColIndex col_b(col_a + 1); col_b < num_cols; ++col_b) {
189 if (AreColumnsProportional(matrix.
column(col_a), matrix.
column(col_b),
191 mapping[col_b] = col_a;
207 for (ColIndex
col(0);
col < num_cols; ++
col) {
217 for (EntryIndex i(0); i <
end; ++i) {
242 const ColIndex first_identity_col =
246 if (
column.num_entries() != 1 ||
247 column.EntryCoefficient(EntryIndex(0)) != 1.0) {
RowIndex EntryRow(EntryIndex i) const
EntryIndex num_entries() const
Fractional EntryCoefficient(EntryIndex i) const
RowIndex num_rows() const
ColIndex num_cols() const
ColumnView column(ColIndex col) const
Fractional EntryCoefficient(EntryIndex i) const
RowIndex EntryRow(EntryIndex i) const
Use a separate API to get the row and coefficient of entry #i.
const SparseColumn & column(ColIndex col) const
Access the underlying sparse columns.
bool IsCleanedUp() const
Call IsCleanedUp() on all columns, useful for doing a DCHECK.
RowIndex num_rows() const
Return the matrix dimension.
ColIndex num_cols() const
EntryIndex num_entries() const
Note this method can only be used when the vector has no duplicates.
bool IsEmpty() const
Returns true if the vector is empty.
constexpr ColIndex kInvalidCol(-1)
ColMapping FindProportionalColumnsUsingSimpleAlgorithm(const SparseMatrix &matrix, Fractional tolerance)
bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix)
Returns true iff the rightmost square matrix is an identity matrix.
ColIndex RowToColIndex(RowIndex row)
Get the ColIndex corresponding to the column # row.
bool AreFirstColumnsAndRowsExactlyEquals(RowIndex num_rows, ColIndex num_cols, const SparseMatrix &matrix_a, const CompactSparseMatrix &matrix_b)
ColMapping FindProportionalColumns(const SparseMatrix &matrix, Fractional tolerance)
In SWIG mode, we don't want anything besides these top-level includes.
util_intops::StrongVector< ColumnEntryIndex, ElementIndex, ElementAllocator > SparseColumn
uint64_t Hash(uint64_t num, uint64_t c)
std::optional< int64_t > end