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;
 
   47    const Fractional coeff_a = a.EntryCoefficient(i);
 
   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)
 
   66      : col(_col), hash(_hash), value(_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;
 
   96ColumnFingerprint ComputeFingerprint(ColIndex col, 
const SparseColumn& column) {
 
   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;
 
  169      if (mapping[col] > col) {
 
  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 =
 
  244  for (ColIndex col = first_identity_col; col < matrix.
num_cols(); ++col) {
 
 
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)
 
StrictITIVector< ColIndex, ColIndex > ColMapping
Row of column indices. Used to represent mappings between columns.
 
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.
 
ClosedInterval::Iterator end(ClosedInterval interval)
 
uint64_t Hash(uint64_t num, uint64_t c)