33 bool AreColumnsProportional(
const SparseColumn&
a,
const SparseColumn&
b,
35 DCHECK(
a.IsCleanedUp());
36 DCHECK(
b.IsCleanedUp());
37 if (
a.num_entries() !=
b.num_entries())
return false;
39 bool a_is_larger =
true;
40 for (
const EntryIndex i :
a.AllEntryIndices()) {
41 if (
a.EntryRow(i) !=
b.EntryRow(i))
return false;
44 if (multiple == 0.0) {
45 a_is_larger = std::abs(coeff_a) > std::abs(coeff_b);
46 multiple = a_is_larger ? coeff_a / coeff_b : coeff_b / coeff_a;
49 if (std::abs(coeff_a / coeff_b - multiple) > tolerance)
return false;
51 if (std::abs(coeff_b / coeff_a - multiple) > tolerance)
return false;
59 struct ColumnFingerprint {
60 ColumnFingerprint(ColIndex _col, int64_t _hash,
double _value)
70 bool operator<(
const ColumnFingerprint& other)
const {
71 if (
hash == other.hash) {
72 return value < other.value;
74 return hash < other.hash;
81 bool AreProportionalCandidates(ColumnFingerprint
a, ColumnFingerprint
b,
83 if (
a.hash !=
b.hash)
return false;
84 return std::abs(
a.value -
b.value) < tolerance;
91 ColumnFingerprint ComputeFingerprint(ColIndex
col,
const SparseColumn&
column) {
92 int64_t non_zero_pattern_hash = 0;
97 non_zero_pattern_hash =
99 sum += e.coefficient();
100 min_abs =
std::min(min_abs, std::abs(e.coefficient()));
101 max_abs =
std::max(max_abs, std::abs(e.coefficient()));
107 DCHECK_NE(0.0, max_abs);
108 const double inverse_dynamic_range = min_abs / max_abs;
109 const double scaled_average =
111 (
static_cast<double>(
column.num_entries().value()) * max_abs);
112 return ColumnFingerprint(
col, non_zero_pattern_hash,
113 inverse_dynamic_range + scaled_average);
120 const ColIndex num_cols = matrix.
num_cols();
124 std::vector<ColumnFingerprint> fingerprints;
125 for (ColIndex
col(0);
col < num_cols; ++
col) {
127 fingerprints.push_back(ComputeFingerprint(
col, matrix.
column(
col)));
130 std::sort(fingerprints.begin(), fingerprints.end());
134 for (
int i = 0; i < fingerprints.size(); ++i) {
135 const ColIndex col_a = fingerprints[i].col;
137 for (
int j = i + 1; j < fingerprints.size(); ++j) {
138 const ColIndex col_b = fingerprints[j].col;
144 if (!AreProportionalCandidates(fingerprints[i], fingerprints[j],
148 if (AreColumnsProportional(matrix.
column(col_a), matrix.
column(col_b),
150 mapping[col_b] = col_a;
158 for (ColIndex
col(0);
col < num_cols; ++
col) {
160 const ColIndex new_representative = mapping[mapping[
col]];
162 mapping[
col] = new_representative;
165 mapping[mapping[
col]] =
col;
176 const ColIndex num_cols = matrix.
num_cols();
178 for (ColIndex col_a(0); col_a < num_cols; ++col_a) {
181 for (ColIndex col_b(col_a + 1); col_b < num_cols; ++col_b) {
184 if (AreColumnsProportional(matrix.
column(col_a), matrix.
column(col_b),
186 mapping[col_b] = col_a;
202 for (ColIndex
col(0);
col < num_cols; ++
col) {
212 for (EntryIndex i(0); i <
end; ++i) {
237 const ColIndex first_identity_col =
241 if (
column.num_entries() != 1 ||
242 column.EntryCoefficient(EntryIndex(0)) != 1.0) {
Fractional EntryCoefficient(EntryIndex i) const
RowIndex EntryRow(EntryIndex i) const
EntryIndex num_entries() const
ColIndex num_cols() const
RowIndex num_rows() const
ColumnView column(ColIndex col) const
Fractional EntryCoefficient(EntryIndex i) const
RowIndex EntryRow(EntryIndex i) const
ColIndex num_cols() const
RowIndex num_rows() const
const SparseColumn & column(ColIndex col) const
typename Iterator::Entry Entry
EntryIndex num_entries() const
constexpr ColIndex kInvalidCol(-1)
bool IsRightMostSquareMatrixIdentity(const SparseMatrix &matrix)
ColMapping FindProportionalColumnsUsingSimpleAlgorithm(const SparseMatrix &matrix, Fractional tolerance)
ColIndex RowToColIndex(RowIndex row)
bool AreFirstColumnsAndRowsExactlyEquals(RowIndex num_rows, ColIndex num_cols, const SparseMatrix &matrix_a, const CompactSparseMatrix &matrix_b)
ColMapping FindProportionalColumns(const SparseMatrix &matrix, Fractional tolerance)
Collection of objects used to extend the Constraint Solver library.
uint64_t Hash(uint64_t num, uint64_t c)
std::optional< int64_t > end