View on GitHub

LinearAlgebra

Library that provides implementations or wrappers for linear algebra operations in C#.

In the examples shown on this page the following matrices will be used.

,

Their initialization for some matrix formats is:

Matrix A = Matrix.CreateFromArray(new double[,] 
{
    { 9.0, 0.0, 3.0, 0.0 },
    { 0.0, 8.0, 0.0, 0.0 },
    { 0.0, 2.0, 6.0, 0.0 },
    { 1.0, 0.0, 0.0, 5.0 }
});

Matrix B = Matrix.CreateFromArray(new double[,] 
{
    { 1.0, 5.0,  9.0, 13.0 },
    { 2.0, 6.0, 10.0, 14.0 },
    { 3.0, 7.0, 11.0, 15.0 },
    { 4.0, 8.0, 12.0, 16.0 }
});

double[] csrValuesA = { 9, 3, 8, 2, 6, 1, 5 };
int[] csrColIndicesA = { 0, 2, 1, 1, 2, 0, 3 };
int[] csrRowOffsetsA = { 0, 2, 3, 5, 7 };
CsrMatrix csrA = CsrMatrix.CreateFromArrays(4, 4, csrValues, csrColIndices, csrRowOffsets, true);

double[] cscValuesA = { 9, 1, 8, 2, 3, 6, 5 };
int[] cscRowIndicesA = { 0, 3, 1, 2, 0 };
int[] cscColOffsetsA = { 0, 2, 4, 6, 7 };
CscMatrix cscA = CsrMatrix.CreateFromArrays(4, 4, cscValues, cscRowIndicesA, cscColOffsetsA, true);

Also make sure that the matrices and vectors have the correct dimensions before applying some operation to them. In debug configurations that will be checked by the LinearAlgebra library as well.

Indexing

We can find the dimensions of a matrix and get or set the entry at some row and column index:

int m = A.NumRows;
int n = csrA.NumColumns;
double A11 = A[1, 1]; // get entry at (row, col)
A[1, 2] = 3.1; // set entry at (row, col)
double A13 = csrA[1, 3]; // 0 will be reuturned
//csrA[1, 3] = 3.0; // this is not allowed, to prevent modification of zero entries

Entrywise operations

Linear combinations:

Operation                  Code
                           IMatrix C;
C = A + B                  C = A.Add(B);
C = A - B                  C = A.Subtract(B);
C = 2 * A                  C = A.Scale(2);
C = B + 2 * A              C = B.Axpy(A, 2)
C = 2 * A + 3 * B          C = B.LinearCombination(3, A, 2);

Variations of the above can be used to overwrite one of the operands, instead of allocating new matrices. However these will fail if they try to overwrite entries of sparse matrix formats that are not explicitly stored. Therefore they should be used only if a dense matrix will be overwritten or if the 2 sparse matrices have the same sparsity pattern.

Operation                  Code
B = A + B                  B.AddIntoThis(A);
B = A - B                  B.SubtractIntoThis(A);
A = 2 * A                  B.ScaleIntoThis(2);
B = B + 2 * A              B.AxpyIntoThis(A, 2);
B = 2 * A + 3 * B          B.LinearCombinationIntoThis(3, A, 2);

User can choose which operation to apply to each entry:

IVector ASquared = A.DoToAllEntries(Aij => Aij * Aij); // Single matrix: ASquared[i, j] = A[i, j] * A[i, j]
IVector C = A.DoEntrywise(B, (Aij, Bij) => (Bij - Aij) / Math.Min(Aij, 0.1)); // Between 2 matrices: C[i, j] = (B[i, j] - A[i, j]) / min(A[i, j], 0.1)

Reductions

Identical to vector reductions. Keep in mind that all entries of the matrix are processed, without taking into account which entries belong to which rows or columns. E.g. you can find the minimum entry of the whole matrix, but not the minimum entry of each column.

Multiplications

Matrix-vector multiplications for almost all matrix formats are supported. When calling these methods, determine whether the transpose of the matrix should be used or not (default). E.g. :

Operation                  Code
                           IVector x = Vector.CreateFromArray(new double[] { 1.1, 2.2, 3.3, 4.4 });
                           IVector y;
y = A * x                  y = A.Multiply(x);
                           y = csrA.Multiply(x); // CSR is optimal for untransposed multiplications
                           y = cscA.Multiply(x);
y = A^T * x                y = A.Multiply(x, true);
                           y = csrA.Multiply(x, true); 
                           y = cscA.Multiply(x, true); // CSC is optimal for transposed multiplications
y = x^T * A                // same as y = A^T * x

Matrix-matrix multiplications for most matrix formats are supported. When calling these methods, determine whether the transpose of the matrices should be used or not (default). E.g. :

Operation                  Code
                           Matrix C;
C = A * B                  C = A.MultiplyRight(B);
                           C = csrA.MultiplyRight(A); // CSR on the left is optimal for untransposed multiplications
C = B * A                  C = A.MultiplyLeft(B);
                           C = cscA.MultiplyLeft(B); // CSC on the right is optimal for untransposed multiplications
C = A^T * B                C = A.MultiplyRight(B, true, false);
                           C = cscA.MultiplyRight(B, true, false); // CSC on the left is optimal for transposed multiplications
C = A * B^T                C = A.MultiplyRight(B, false, true);
C = A^T * B^T              C = A.MultiplyRight(B, true, true);

Transposition

Usually transposing a matrix is needed during multiplication, in which case it is done implicitly by using the correct flag in the multiplication method call, as shown in Multiplications. Nevertheless, it is possible to explicitly transpose a matrix, at the cost of extra memory:

Matrix transposeA = A.Transpose();

// In this case, no extra memory is needed. However modifying one of csrA, cscTransposeA will also modify the other.
bool copyInternalArrays = false;
CscMatrix cscTransposeA = csrA.TransposeToCSC(copyInternalArrays); 

Join matrices

We can join 2 matrices by putting:

Matrix D = A.AppendRight(B);
Marix E = A.AppendBottom(B);

Operations at only some rows & columns

Extract a single row, column or the diagonal (only for square matrices):

Vector row1 = A.GetRow(1);
Vector col2 = A.GetColumn(2);
Vector diagonal = A.GetDiagonal();

Modify a row or column or part of it:

// Set the whole row 1
int row1 = 1;
int start = 0;
Vector newValues = Vector.CreateFromArray(new double[] { 1.1, 2.2, 3.3, 4.4 };)
A.SetSubrow(row1, newValues, start);

// Set the second half of column 2
int col2 = 2;
start = 2;
newValues = Vector.CreateFromArray(new double[] { 3.3, 4.4 };)
A.SetSubcolumn(col2, newValues, start);

Extract the submatrices

// Extract submatrix from (0, 0) to (1, 2)
Matrix Asub1 = A.GetSubmatrix(0, 2, 0, 3);

// Extract rows and columns 0, 3, but also reverse them:
Matrix Asub2 = A.GetSubmatrix(new int[] { 3, 0 }, new int[] { 3, 0 });

Set all entries of the submatrix Asub1 to 3.14:

Matrix newValues = Matrix.CreateZero(3, 3);
newValues.SetAll(3.14);
Matrix Asub1 = A.SetSubmatrix(0, 0, newValues);