31bool AreColumnsProportional(
const SparseColumn&
a,
const SparseColumn&
b,
35 if (
a.num_entries() !=
b.num_entries())
return false;
37 bool a_is_larger =
true;
38 for (
const EntryIndex i :
a.AllEntryIndices()) {
39 if (
a.EntryRow(i) !=
b.EntryRow(i))
return false;
42 if (multiple == 0.0) {
43 a_is_larger = std::abs(coeff_a) > std::abs(coeff_b);
44 multiple = a_is_larger ? coeff_a / coeff_b : coeff_b / coeff_a;
47 if (std::abs(coeff_a / coeff_b - multiple) > tolerance)
return false;
49 if (std::abs(coeff_b / coeff_a - multiple) > tolerance)
return false;
57struct ColumnFingerprint {
58 ColumnFingerprint(ColIndex _col, int64_t _hash,
double _value)
68 bool operator<(
const ColumnFingerprint& other)
const {
69 if (
hash == other.hash) {
70 return value < other.value;
72 return hash < other.hash;
79bool AreProportionalCandidates(ColumnFingerprint
a, ColumnFingerprint
b,
81 if (
a.hash !=
b.hash)
return false;
82 return std::abs(
a.value -
b.value) < tolerance;
89ColumnFingerprint ComputeFingerprint(ColIndex
col,
const SparseColumn& column) {
90 int64_t non_zero_pattern_hash = 0;
95 non_zero_pattern_hash =
97 sum += e.coefficient();
98 min_abs =
std::min(min_abs, std::abs(e.coefficient()));
99 max_abs =
std::max(max_abs, std::abs(e.coefficient()));
106 const double inverse_dynamic_range = min_abs / max_abs;
107 const double scaled_average =
109 (
static_cast<double>(column.num_entries().value()) * max_abs);
110 return ColumnFingerprint(
col, non_zero_pattern_hash,
111 inverse_dynamic_range + scaled_average);
118 const ColIndex num_cols = matrix.
num_cols();
122 std::vector<ColumnFingerprint> fingerprints;
123 for (ColIndex
col(0);
col < num_cols; ++
col) {
125 fingerprints.push_back(ComputeFingerprint(
col, matrix.
column(
col)));
128 std::sort(fingerprints.begin(), fingerprints.end());
132 for (
int i = 0; i < fingerprints.size(); ++i) {
133 const ColIndex col_a = fingerprints[i].col;
135 for (
int j = i + 1; j < fingerprints.size(); ++j) {
136 const ColIndex col_b = fingerprints[j].col;
142 if (!AreProportionalCandidates(fingerprints[i], fingerprints[j],
146 if (AreColumnsProportional(matrix.
column(col_a), matrix.
column(col_b),
148 mapping[col_b] = col_a;
156 for (ColIndex
col(0);
col < num_cols; ++
col) {
158 const ColIndex new_representative = mapping[mapping[
col]];
160 mapping[
col] = new_representative;
163 mapping[mapping[
col]] =
col;
174 const ColIndex num_cols = matrix.
num_cols();
176 for (ColIndex col_a(0); col_a < num_cols; ++col_a) {
179 for (ColIndex col_b(col_a + 1); col_b < num_cols; ++col_b) {
182 if (AreColumnsProportional(matrix.
column(col_a), matrix.
column(col_b),
184 mapping[col_b] = col_a;
200 for (ColIndex
col(0);
col < num_cols; ++
col) {
210 for (EntryIndex i(0); i < end; ++i) {
235 const ColIndex first_identity_col =
#define DCHECK_NE(val1, val2)
#define DCHECK(condition)
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
const SparseColumn & column(ColIndex col) const
RowIndex num_rows() const
typename Iterator::Entry Entry
EntryIndex num_entries() const
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)
const ColIndex kInvalidCol(-1)
Collection of objects used to extend the Constraint Solver library.
uint64_t Hash(uint64_t num, uint64_t c)