Decompressing CVS, CRS and CCS

If you can compress them, you can decompress them, right? Decompression helps to validate the compression. In this article, I'll explore how CVS, CRS and CCS can be decompressed to a two-dimensional array T[,] dense matrix. .

CVS, CRS and CCS have CVSExtensions, CRSExtensions and CCSExtensions respectively. These provide extension methods that can operate on the compressed matrix. We already saw how matrix-vector multiplication can be added. Adding Decompress() is a similar exercise.

CVS, CRS and CCS each already has a Decompress() method that saves to a new sparse matrix. The Decompress() extension methods overload that to return the two-dimensional array matrix T[,] version.

CVS

In CVSExtensions, add the following:

        public static T[,] Decompress<T>(this CVS<T> cvs, 
            T defaultValue = default(T), T diagonal = default(T))
        {
            (List<T> value, 
             List<List<int>> linearIndex, 
             MatrixLinearIndexMode linearIndexMode, 
             (int rows, int columns) size) = cvs;
            T[,] denseMatrix = Matrix<T>.Create(size, defaultValue, diagonal);
            for (int i = 0; i < value.Count; i++)
            {
                T v = value[i];
                foreach (var li in linearIndex[i])
                {
                    (int row, int column) = 
                        MatrixCoordinates.ToCoordinates(size, li, linearIndexMode);
                    denseMatrix[row, column] = v;
                }
            }
            return denseMatrix;
        }

Observe the need to convert CVS's linear indexes into their coordinates equivalent.

CRS

In CRSExtensions, add the following:

        public static T[,] Decompress<T>(this CRS<T> crs, 
            T defaultValue = default(T), T diagonal = default(T))
        {
            (List<T> value, 
             List<int> rowPointer, 
             List<int> columnIndex, 
             (int rows, int columns) size) = crs;
            T[,] denseMatrix = Matrix<T>.Create(size, defaultValue, diagonal);
            for (int j = 0; j < size.rows; j++)
            {
                for (int i = rowPointer[j]; i < rowPointer[j + 1]; i++)
                {
                    denseMatrix[j, columnIndex[i]] = value[i];
                }
            }
            return denseMatrix;
        }

Note the use of the 4th tuple item "size" to initialize the dense matrix. In CRS, the original matrix's number of columns is lost. This is the reason why the CRS tuple in Mendz.Library.Matrices adds the 4th item (int rows, int columns) size.

CCS

In CCSExtensions, add the following:

        public static T[,] Decompress<T>(this CCS<T> ccs, 
            T defaultValue = default(T), T diagonal = default(T))
        {
            (List<T> value, 
             List<int> columnPointer, 
             List<int> rowIndex, 
             (int rows, int columns) size) = ccs;
            T[,] denseMatrix = Matrix<T>.Create(size, defaultValue, diagonal);
            for (int j = 0; j < size.columns; j++)
            {
                for (int i = columnPointer[j]; i < columnPointer[j + 1]; i++)
                {
                    denseMatrix[rowIndex[i], j] = value[i];
                }
            }
            return denseMatrix;
        }

Note the use of the 4th tuple item "size" to initialize the dense matrix. In CCS, the original matrix's number of rows is lost. This is the reason why the CCS tuple in Mendz.Library.Matrices adds the 4th item (int rows, int columns) size.

And that's how easy it is to add decompressing to a dense matrix T[,] via extension methods. Note that extension methods are static. Default optimizations in .Net load them JIT at runtime. This helps making the actual type to be "compact" by default. The extensions are only loaded when they are actually called or used.

Comments