Mendz.Library.Matrices

I re-organized Mendz.Library and created a separate Mendz.Library.Matrices project for the growing list of matrix-specific types and classes that started popping up while working on matrix compressions. This enhancement is big!

The goal is to improve modularization. Mendz.Library is referenced by the Mendz.Data* projects, which have no use for matrices. By separating the matrices to their own project (and, therefore, separate .DLL), the availability of the matrix types and classes can instead be deliberate and explicit.

New Matrix Types and Classes

The following new types and classes are created in Mendz.Library.Matrices:
  • IDOKSparseMatrix defines a dictionary of keys (DOK) sparse matrix.
  • DOKSparseMatrixBase is the base class of sparse matrices.
  • DOKSparseMatrix defines a sparse matrix. This is the default implementation of DOKSparseMatrixBase.
  • DOKConcurrentSparseMatrix derives DOKSparseMatrixBase to define a thread-safe sparse matrix.
  • CoordinatesKeyedSparseMatrix derives DOKSparseMatrix to define a coordinates keyed sparse matrix.
  • CoordinatesKeyedConcurrentSparseMatrix derives DOKConcurrentSparseMatrix to define a thread-safe coordinates keyed sparse matrix.
  • LinearIndexKeyedSparseMatrix derives DOKSparseMatrix to define a linear index keyed sparse matrix.
  • LinearIndexKeyedConcurrentSparseMatrix derives DOKConcurrentSparseMatrix to define a thread-safe linear index keyed sparse matrix.
  • SparseMatrixFactory provides methods to create sparse matrix instances.
  • MatrixLinearIndexMode is an enumeration of values RowMajorOrder (0) and ColumnMajorOrder (1), which are used by MatrixCoordinates methods.
  • MatrixCoordinates provides the methods to operate on matrix coordinates and/or linear indexes.
  • CVS represents matrices in compressed value storage (CVS) format.
  • CVSExtensions provides extension methods to CVS.
  • CRS represents matrices in compressed row storage (CRS) format.
  • CRSExtensions provides extension methods to CRS.
  • CCS represents matrices in compressed column storage (CCS) format.
  • CCSExtensions provides extension methods to CCS.
  • IDOKSparseMatrixExtensions provides extension methods to IDOKSparseMatrix.
  • MDAS enumeration of operations Multiply, Divide, Add and Substract.
As a result of the new MatrixCoordinates class, the Matrix and SquareMatrix classes remove their ToLinearIndex(), ToCoordinates() and CheckCoordinates() methods.

MatrixCoordinates.cs
using System;

namespace Mendz.Library.Matrices
{
    public static class MatrixCoordinates
    {
        public static int ToLinearIndex((int rows, int columns) size, int row, int column, 
            MatrixLinearIndexMode linearIndexMode = MatrixLinearIndexMode.RowMajorOrder)
        {
            if (linearIndexMode == MatrixLinearIndexMode.RowMajorOrder)
            {
                return column + (row * size.columns);
            }
            else // MatrixLinearIndexMode.ColumnMajorOrder
            {
                return row + (column * size.rows);
            }
        }

        public static int ToLinearIndex((int rows, int columns) size, 
            (int row, int column) coordinates, 
            MatrixLinearIndexMode linearIndexMode = MatrixLinearIndexMode.RowMajorOrder)
        {
            return ToLinearIndex(size, coordinates.row, coordinates.column, 
                linearIndexMode);
        }

        public static int ToLinearIndex(int order, int row, int column, 
            MatrixLinearIndexMode linearIndexMode = MatrixLinearIndexMode.RowMajorOrder)
        {
            return ToLinearIndex((order, order), row, column, linearIndexMode);
        }

        public static int ToLinearIndex(int order, (int row, int column) coordinates, 
            MatrixLinearIndexMode linearIndexMode = MatrixLinearIndexMode.RowMajorOrder)
        {
            return ToLinearIndex((order, order), coordinates.row, coordinates.column, 
                linearIndexMode);
        }

        public static (int row, int column) ToCoordinates((int rows, int columns) size, 
            int linearIndex, 
            MatrixLinearIndexMode linearIndexMode = MatrixLinearIndexMode.RowMajorOrder)
        {
            if (linearIndexMode == MatrixLinearIndexMode.RowMajorOrder)
            {
                return ((int)(linearIndex / size.columns), linearIndex % size.columns);
            }
            else // MatrixLinearIndexMode.ColumnMajorOrder
            {
                return (linearIndex % size.rows, (int)(linearIndex / size.rows));
            }
        }

        public static (int row, int column) ToCoordinates(int order, int linearIndex, 
            MatrixLinearIndexMode linearIndexMode = MatrixLinearIndexMode.RowMajorOrder)
        {
            return ToCoordinates((order, order), linearIndex);
        }

        public static bool CheckCoordinates((int rows, int columns) size, 
            int row, int column, bool suppressException = false)
        {
            bool isOK = true;
            if (isOK && (row < 0 || row >= size.rows))
            {
                if (suppressException)
                {
                    isOK = false;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("row");
                }
            }
            if (isOK && (column < 0 || column >= size.columns))
            {
                if (suppressException)
                {
                    isOK = false;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("column");
                }
            }
            return isOK;
        }

        public static bool CheckCoordinates((int rows, int columns) size, 
            (int row, int column) coordinates, bool suppressException = false)
        {
            return CheckCoordinates(size, coordinates.row, coordinates.column, 
                suppressException);
        }

        public static void CheckCoordinates(int order, int row, int column, 
            bool suppressException = false)
        {
            CheckCoordinates((order, order), row, column, suppressException);
        }

        public static void CheckCoordinates(int order, (int row, int column) coordinates, 
            bool suppressException = false)
        {
            CheckCoordinates((order, order), coordinates, suppressException);
        }
    }
}

This code defines the MatrixCoordinates static class. Note that it includes method overloads for square matrices (versions with "int order" as parameter). ToLinearIndex() converts coordinates to linear index. ToCoordinates() converts linear index to coordinates. Note that ToLinearIndex() and ToCoordinates() must be used together with a consistent MatrixLinearIndexMode (row- or column-major order). CheckCoordinates() can be used to help validate coordinates in indexers that simulate matrix-like access.

Impacts to Mendz.Graphs

Mendz.Graphs dropped its reference to Mendz.Library to reference Mendz.Library.Matrices instead. Thus, all "using Mendz.Library;" statements in Mendz.Graphs just needs to be replaced with "using Mendz.Library.Matrices".

SparseGraphMatrixBase has been updated to be a wrapper to the Mendz.Library.Matrices.CoordinatesKeyedConcurrentSparseMatrix class. A new SparseMatrix property is added. The affected members are the indexer, which now calls the SparseMatrix indexer; and Initialize(), which should now initialize the new SparseMatrix property.

        ....

        public CoordinatesKeyedConcurrentSparseMatrix SparseMatrix { get; protected set; }
 
        ...

        public T this[int row, int column]
        {
            get
            {
                return SparseMatrix[row, column];
            }
        }

        ...

        public override void Initialize()
        {
            SparseMatrix = new CoordinatesKeyedConcurrentSparseMatrix<T>(Size);
            Matrix = SparseMatrix.Matrix;
        }

        ...

This change affects Mendz.Graphs..Sparse.AdjacecyMatrixBase. Its indexer override is removed. Initialize() is also updated to make sure that the inherited SparseMatrix property is initialized with the NonAdjacent and Diagonal properties values.

        public override void Initialize()
        {
            SparseMatrix = new CoordinatesKeyedConcurrentSparseMatrix<T>(
                Size, NonAdjacent, Diagonal);
            Matrix = SparseMatrix.Matrix;
        }

Now, about that CoordinatesKeyedConcurrentSparseMatrix...

Comments