Triangular Matrices

A matrix whose elements above or below the main diagonal are all zero. The name derives from the fact that the shape of the non-zero elements resembles a triangle. Triangular matrices are implemented by the TriangularMatrix<T> class.

How triangular matrices are stored

Triangular matrices can be upper or lower triangular. An upper triangular matrix has non-zero elements on and above the main diagonal. A lower triangular matrix has non-zero elements on and below the main diagonal. The MatrixTriangle property is of enumeration type MatrixTriangle and can have values Upper and Lower.

Strictly speaking, triangular matrices are always square. If an upper triangular matrix has more columns than rows, then the shape of the block of the non-zero elements is more trapezoidal than triangular. Such upper-trapezoidal matrices and their lower-trapezoidal counterparts are also represented using the TriangularMatrix<T> class.

The main diagonal of a triangular matrix can have arbitrary elements, or it can be constrained to only consist of 1's. The MatrixDiagonal property indicates which of these two is the case. It is of type MatrixDiagonal and can have values UnitDiagonal and NonUnitDiagonal (the default).

Constructing triangular matrices

Triangular matrices are constructed in a way analogous to dense matrices, using the CreateUpperTriangular and CreateLowerTriangular methods of the Matrix class. These methods have several overloads.

The simplest overload takes one argument. It returns a square matrix with the specified number of rows and columns. The element type must be specified as a generic type argument. All elements are initially set to zero. For example, for a 5x5 upper triangular matrix, we have:

C#
var t1 = Matrix.CreateUpperTriangular<double>(5);

You can also specify both the number of rows and columns. The following creates a 5x7 upper-trapezoidal matrix:

C#
var t2 = Matrix.CreateUpperTriangular<double>(5, 7);

If the matrix is unit diagonal, you can specify this by adding a third argument of type MatrixDiagonal. If this argument has the value UnitDiagonal, all elements except the elements on the main diagonal are initially set to zero. The elements on the diagonal are all equal to one and cannot be changed. For example:

C#
var t3 = Matrix.CreateLowerTriangular<double>(5, 5,
    MatrixDiagonal.UnitDiagonal);

creates a 5x5 lower triangular matrix with unit diagonal.

The three remaining overloads are similar to the previous three, but also let you initialize the elements of the matrix. This is done through two additional arguments. The first is an array that contains the matrix elements. THe second is a MatrixElementOrder value that specifies whether the elements are listed in column-major or row-major order.

C#
double[] elements = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var t4 = Matrix.CreateUpperTriangular(3, 3, elements, MatrixElementOrder.ColumnMajor);
// t4 -> [[ 1 4 7 ]
//        [ 0 5 8 ]
//        [ 0 0 9 ]]
var t5 = Matrix.CreateUpperTriangular(3, 3, elements, MatrixElementOrder.RowMajor);
// t4 -> [[ 1 2 3 ]
//        [ 0 5 6 ]
//        [ 0 0 9 ]]

Finally, the most complete and flexible overload lets you specify the order of the elements, whether the matrix is unit diagonal, and whether to reuse the element array for storage:

C#
var t6 = Matrix.CreateUpperTriangular(
    3, 3, elements, MatrixDiagonal.UnitDiagonal,
    MatrixElementOrder.RowMajor, true);

Extracting triangular matrices

You may have an existing matrix whose upper or lower triangular part you wish to reuse as if it were a triangular matrix with all other elements being zero. The Matrix.ExtractLowerTriangle and Matrix.ExtractUpperTriangle methods provide this functionality. You can extract triangular matrices from dense and symmetrical or Hermitian matrices. You can also specify whether the new matrix is unit diagonal.

The following example splits a dense matrix into an upper triangular and a unit-diagonal lower triangular part:

C#
var m = Matrix.Create(3, 3, elements, MatrixElementOrder.RowMajor);
// m -> [[ 1 2 3 ]
//       [ 4 5 6 ]
//       [ 7 8 9 ]]
var u = Matrix.ExtractUpperTriangle(m);
// u -> [[ 1 2 3 ]
//       [ 0 5 6 ]
//       [ 0 0 9 ]]
var l = Matrix.ExtractLowerTriangle(m, MatrixDiagonal.UnitDiagonal);
// l -> [[ 1 0 0 ]
//       [ 4 1 0 ]
//       [ 7 8 1 ]]