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 using factory methods in the Matrix class. There are separate methods for creating upper and lower triangular matrices. Use CreateUpperTriangular for upper triangular matrices and CreateLowerTriangular for lower triangular matrices.
The simplest way is to create a triangular matrix with all non-diagonal elements set to zero. It takes one argument for square matrices or two arguments for rectangular (trapezoidal) matrices. The element type must be specified as a generic type argument. For example, for a 5x5 upper triangular matrix, we have:
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:
var t2 = Matrix.CreateUpperTriangular<double>(5, 7);If the matrix has a unit diagonal (all diagonal elements are 1 and cannot be changed), you can specify this by adding an argument of type MatrixDiagonal. If this argument has the value UnitDiagonal, all off-diagonal elements are initially set to zero and the diagonal elements are fixed at 1. For example:
var t3 = Matrix.CreateLowerTriangular<double>(5, 5,
MatrixDiagonal.UnitDiagonal);creates a 5x5 lower triangular matrix with unit diagonal.
To create a triangular matrix from existing data by copying, use the CopyFromUpperTriangular``1(UMP[], Int32, Int32, MatrixElementOrder, MatrixDiagonal, ArrayMutability) or CopyFromLowerTriangular``1(UMP[], Int32, Int32, MatrixElementOrder, MatrixDiagonal, ArrayMutability) methods. The first argument is an array that contains the matrix elements. The second and third arguments specify the number of rows and columns. The fourth argument is a MatrixElementOrder value that specifies whether the elements are listed in column-major or row-major order.
double[] elements = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var t4 = Matrix.CopyFromUpperTriangular(elements, 3, 3, elementOrder: MatrixElementOrder.ColumnMajor);
// t4 -> [[ 1 4 7 ]
// [ 0 5 8 ]
// [ 0 0 9 ]]
var t5 = Matrix.CopyFromUpperTriangular(elements, 3, 3, elementOrder: MatrixElementOrder.RowMajor);
// t4 -> [[ 1 2 3 ]
// [ 0 5 6 ]
// [ 0 0 9 ]]To create a triangular matrix that wraps an existing array without copying (creating a "view"), use the WrapUpperTriangular``1(UMP[], Int32, Int32, MatrixElementOrder, MatrixDiagonal, ArrayMutability) or WrapLowerTriangular``1(UMP[], Int32, Int32, MatrixElementOrder, MatrixDiagonal, ArrayMutability) methods. Any changes to the wrapped array will affect the matrix, and vice versa.
var t6 = Matrix.WrapUpperTriangular(
elements, 3, 3,
MatrixDiagonal.UnitDiagonal, MatrixElementOrder.RowMajor);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:
var m = Matrix.CopyFrom(elements, 3, 3, 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 ]]