Dense Matrices

A DenseMatrix<T> represents a dense matrix with arbitrary elements.

How dense matrices are stored

The elements of a DenseMatrix<T> are stored in a one-dimensional array. The elements can be stored in two ways: column major and row major. Column major order means that the elements of each column are stored in adjacent elements of the array. Row major order means that the elements of each row are stored in adjacent elements of the array.

For historical reasons, most linear algebra algorithms have been optimized for column major storage. For this reason, column major order is the default. Row major order is supported transparently. Conversions are performed when necessary. Very often, row major order can be used without any significant loss of speed.

The element order is usually only important when initializing the elements of a matrix. No application should have any other explicit dependency on the way matrix elements are stored.

The element order is given by the ElementOrder property, which is of type MatrixElementOrder. Possible values are ColumnMajor, RowMajor and NotApplicable.

Constructing general dense matrices

Dense matrices are constructed using factory methods in the Matrix class. Method names clearly indicate what happens with data: whether a matrix is created from scratch, copied from existing data, or wraps existing data. All methods take a generic type argument that specifies the element type. In most cases, type inference eliminates the need to specify the element type explicitly.

The Zeros``1(Int32, Int32) method creates a matrix with all elements initialized to zero. It takes two arguments: the number of rows and the number of columns in the matrix. The element type must be specified as the generic type argument. The example below creates a matrix with 3 rows and 4 columns:

C#
var m1 = Matrix.Zeros<double>(3, 4);

An optional third argument specifies the order in which matrix elements are stored. This argument is of the MatrixElementOrder enumeration type. The following creates a matrix with 3 rows and 4 columns, whose elements are stored in row major order:

C#
var m2 = Matrix.Zeros<double>(3, 4, MatrixElementOrder.RowMajor);

To create a matrix from existing data, use the [M:Numerics.NET.Matrix.CopyFrom``1(``0[0:,0:])] method. It takes a 2-dimensional array and creates a new matrix by copying the data. For a one-dimensional array, use CopyFrom``1(UMP[], Int32, Int32, MatrixElementOrder). This method takes the array, the dimensions of the matrix, and a MatrixElementOrder value that specifies whether the elements in the array are listed row-wise or column-wise.

The example below shows three ways to create the same matrix: from a 2D array, from a 1D array in column-major order, and from a 1D array in row-major order:

C#
double[,] elements2D = { { 11, 12, 21 }, { 22, 31, 32 } };
var m3 = Matrix.CopyFrom(elements2D);
double[] elements = { 11, 21, 31, 12, 22, 32 };
var m4 = Matrix.CopyFrom(elements, 3, 2, MatrixElementOrder.ColumnMajor);
double[] elementsByRow = { 11, 12, 21, 22, 31, 32 };
var m5 = Matrix.CopyFrom(elementsByRow, 3, 2, MatrixElementOrder.RowMajor);

The CopyFrom methods always copy the data to ensure the matrix has independent storage. To create a matrix that wraps an existing array without copying (creating a "view"), use the Wrap``1(UMP[], Int32, Int32, MatrixElementOrder) method instead. This method has the same signature as CopyFrom but reuses the array for internal storage.

It is important to note the effects of wrapping an array. Any change to an element of the wrapped array will change the corresponding element of the matrix, and vice versa. In general, the wrapped array should not be used for any other purpose.

The FromFunction``1(Int32, Int32, Func<Int32, Int32, UMP>) method creates a matrix whose elements are initialized by a function. It takes the dimensions of the matrix and a delegate that maps the row and column index of each element to its value:

C#
var m6 = Matrix.FromFunction(4, 4, (i, j) => 1.0 / (1.0 + i + j));