Matrix Basics

Matrices come in many shapes and sizes. When the matrix exhibits a definite structure, calculations can often be speeded up by several orders of magnitude. Storage requirements may also be significantly reduced. It is therefore useful to define different matrix types to take advantage of these improvements.

Numerics.NET includes classes for dense matrices, upper- and lower-triangular matrices, symmetric or Hermitian matrices, and sparse matrices.

The Matrix<T> class is an abstract base class that exposes the mathematical methods and properties of matrices of arbitrary types. It also contains a default implementation for these methods and properties. A series of derived classes implement specific types of matrices. These are listed in the table below.

Class

Description

DenseMatrix<T>

A standard dense matrix. All elements can take on any value. This is the most common type.

TriangularMatrix<T>

A matrix whose elements above or below the main diagonal are all zero.

SymmetricMatrix<T>

A matrix whose elements are symmetrical about the main diagonal. A symmetric matrix is equal to its transpose.

SparseMatrix<T>

A matrix whose elements are mostly zero. Only the nonzero elements are stored.

MatrixView<T>

A matrix that represents a range or slice of another matrix.

The Matrix<T> class does not specify how matrix elements should be stored. This is left entirely up to the derived classes. The derived matrix types provide their own optimized implementations for many of the base methods and properties. Wherever possible, use is made of optimized implementations of the standard Basic Linear Algebra Subroutines (BLAS) and the Linear Algebra PACKage (LAPACK).

Some matrix types put restrictions on the elements that can be changed. For example, you can only modify the non-zero elements of a TriangularMatrix<T>. If you try to assign a value to a read-only element, an exception of type ComponentReadonlyException is thrown. You can check whether an element is writable by calling the IsElementWritable(Int32, Int32) method with the row and column index of the element.

A DenseMatrix<T> can be used to represent any matrix. It is the only matrix type whose elements are all guaranteed to be writable.

Copying matrices

There are three ways to make a copy of a matrix.

The ShallowCopy method creates a derived matrix that is a memberwise clone of the original. The new matrix has the same type and dimensions as the original matrix. When you change the value of an element of this matrix, the value of the corresponding element in the original matrix changes as well, and vice versa.

The Clone method, which implements the ICloneable interface, creates a stand-alone matrix that is a complete copy of the original. This method creates a matrix of the same type as the original, and makes its own copy of the element storage. When you change the value of an element of this matrix, the value of the corresponding element in the original matrix does not change. Likewise, if you change the value of an element of the original matrix, the value of the corresponding element in the copied matrix does not change.

You can convert a shallow copy to a full copy by calling the CloneData method. This method ensures that an instance has its own copy of the data. After a call to this method, any changes to the elements of this matrix will only affect this instance.

C#
// Create a vector, a shallow copy, and a clone:
Matrix m = Matrix.Create(2, 2);
m[1,1] = 2;
Matrix mShallowCopy = m.ShallowCopy();
Matrix mClone = m.Clone();
// This prints '2':
Console.WriteLine("m[1,1] = {0}", m[1,1]);
// Now change the value of this component.
m[1,1] = -1;
// Component changed. This prints '-1':
Console.WriteLine("m[1,1] = {0}", m[1,1]);
// Shallow copy changed, also. This prints '-1':
Console.WriteLine("mShallowCopy[1,1] = {0}", mShallowCopy[1,1]);
// Clone is left unchanged. This prints '2':
Console.WriteLine("mClone[1,1] = {0}", mClone[1,1]);

The third way to copy a vector is by calling the vector's ToDenseMatrix method. This method returns a stand-alone Matrix<T> whose elements are copied from the original matrix. If this method is called on a DenseMatrix<T>, a new matrix is still created. In all cases, the elements of the new matrix are guaranteed to be stored in a contiguous block of memory.

You can copy the elements of a matrix to another, previously created vector using the CopyTo method. Care should be taken that you don't try to modify elements that are read-only. Any such attempt will result in a ComponentReadOnlyException.