public static IEnumerable <int> GetColWeights(IBitMatrix matrix) { for (int col = 0; col < matrix.Cols; col++) { yield return(matrix.GetColWeight(col)); } }
private IBitMatrix CompactMatrix() { var deletedRows = new bool[matrix.Rows]; var deletedCols = new bool[matrix.Cols]; ancestors = new Ancestor[matrix.Cols]; for (int i = 0; i < matrix.Cols; i++) { ancestors[i] = new Ancestor { Column = i } } ; if (diagnostics) { Console.WriteLine("initial density = {0:F3}/col", (double)matrix.GetRowWeights().Sum() / matrix.Rows); } int surplusCols = 0; int pass = 1; while (true) { int deleted = 0; for (int n = matrix.Rows - 1; n >= 0; n--) { if (deletedRows[n]) { continue; } var weight = matrix.GetRowWeight(n); // Delete entirely empty rows. if (weight == 0) { deletedRows[n] = true; ++surplusCols; ++deleted; continue; } // Delete rows with a single non-zero entry. if (weight == 1) { var col = matrix.GetNonZeroCols(n).First(); deletedRows[n] = true; MergeColumns(col); deletedCols[col] = true; ++deleted; continue; } // Use surplus rows to bring weight down to merge limit. int limit = Math.Min(pass, mergeLimit); if (weight > limit && surplusCols > 0 && weight - surplusCols <= limit) { while (weight > limit) { var col = matrix.GetNonZeroCols(n) .OrderByDescending(index => matrix.GetColWeight(index)) .First(); MergeColumns(col); deletedCols[col] = true; ++deleted; --surplusCols; --weight; } } // Merge low weight rows. if (weight <= limit) { var cols = matrix.GetNonZeroCols(n) .OrderByDescending(index => matrix.GetColWeight(index)) .ToArray(); Debug.Assert(cols.Length == weight); var srcCol = cols[0]; MergeColumns(cols); for (var ancestor = ancestors[srcCol]; ancestor != null; ancestor = ancestor.Next) { for (int j = 1; j < weight; j++) { ancestors[cols[j]] = new Ancestor { Column = ancestor.Column, Next = ancestors[cols[j]] } } ; } deletedRows[n] = true; ancestors[srcCol] = null; deletedCols[srcCol] = true; ++deleted; continue; } } if (diagnostics) { Console.WriteLine("pass {0}: deleted {1} rows", pass, deleted); } if (deleted == 0) { break; } ++pass; } // Compute mapping between original matrix and compact matrix. ancestors = deletedCols .Select((deleted, index) => deleted ? null : ancestors[index]) .Where(ancestor => ancestor != null) .ToArray(); var rowMap = deletedRows .Select((deleted, index) => deleted ? -1 : index) .Where(index => index != -1) .ToArray(); var colMap = deletedCols .Select((deleted, index) => deleted ? -1 : index) .Where(index => index != -1) .ToArray(); // Permute columns to sort by increasing column weight. var order = Enumerable.Range(0, colMap.Length) .OrderBy(index => matrix.GetColWeight(colMap[index])) .ToArray(); ancestors = Enumerable.Range(0, colMap.Length) .Select(index => ancestors[order[index]]) .ToArray(); colMap = Enumerable.Range(0, colMap.Length) .Select(index => colMap[order[index]]) .ToArray(); // Create compact matrix. var revColMap = new int[matrix.Cols]; for (int i = 0; i < colMap.Length; i++) { revColMap[colMap[i]] = i; } var compactMatrix = (IBitMatrix)Activator.CreateInstance(typeof(TMatrix), rowMap.Length, colMap.Length); for (int i = 0; i < rowMap.Length; i++) { int row = rowMap[i]; foreach (var col in matrix.GetNonZeroCols(row)) { compactMatrix[i, revColMap[col]] = true; } } if (diagnostics) { Console.WriteLine("completed compaction in {0} passes", pass); Console.WriteLine("final density = {0:F3}/col", (double)matrix.GetRowWeights().Sum() / compactMatrix.Rows); } return(compactMatrix); }
public static IEnumerable<int> GetColWeights(IBitMatrix matrix) { for (int col = 0; col < matrix.Cols; col++) yield return matrix.GetColWeight(col); }