Symmetric, Skew-Symmetric and Triangular Matrices.
Among the special arrays implemented in GeometricMachineLearning
SymmetricMatrix
, SkewSymMatrix
, UpperTriangular
and LowerTriangular
are the most common ones and similar implementations can also be found in other libraries; LinearAlgebra.jl
has an implementation of a symmetric matrix called Symmetric
for example. The versions of these matrices in GeometricMachineLearning
are however more memory efficient as they only store as many parameters as are necessary, i.e. $n(n+1)/2$ for the symmetric matrix and $n(n-1)/2$ for the other three. In addition operations such as matrix and tensor multiplication are implemented for these matrices to work in parallel on GPU via GeometricMachineLearning.tensor_mat_mul
for example. We here give an overview of elementary custom matrices that are implemented in GeometricMachineLearning
. More involved matrices are the so-called global tangent spaces.
Custom Matrices
GeometricMachineLearning
has two types of triangular matrices. The first one is UpperTriangular
:
\[U = \begin{pmatrix} 0 & a_{12} & \cdots & a_{1n} \\ 0 & \ddots & & a_{2n} \\ \vdots & \ddots & \ddots & \vdots \\ 0 & \cdots & 0 & 0 \end{pmatrix}.\]
And the second one is LowerTriangular
:
\[L = \begin{pmatrix} 0 & 0 & \cdots & 0 \\ a_{21} & \ddots & & \vdots \\ \vdots & \ddots & \ddots & \vdots \\ a_{n1} & \cdots & a_{n(n-1)} & 0 \end{pmatrix}.\]
An instance of SkewSymMatrix
can be written as $A = L - L^T$ or $A = U^T - U$:
\[A = \begin{pmatrix} 0 & - a_{21} & \cdots & - a_{n1} \\ a_{21} & \ddots & & \vdots \\ \vdots & \ddots & \ddots & \vdots \\ a_{n1} & \cdots & a_{n(n-1)} & 0 \end{pmatrix}.\]
And lastly a SymmetricMatrix
:
\[B = \begin{pmatrix} a_{11} & a_{21} & \cdots & a_{n1} \\ a_{21} & \ddots & & \vdots \\ \vdots & \ddots & \ddots & \vdots \\ a_{n1} & \cdots & a_{n(n-1)} & a_{nn} \end{pmatrix}.\]
Note that any matrix $M\in\mathbb{R}^{n\times{}n}$ can be written
\[M = \frac{1}{2}(M - M^T) + \frac{1}{2}(M + M^T),\]
where the first part of this matrix is skew-symmetric and the second part is symmetric. This is also how the constructors for SkewSymMatrix
and SymmetricMatrix
are designed. Consider an arbitrary matrix:
M = [1; 2; 3;; 4; 5; 6;; 7; 8; 9]
3×3 Matrix{Int64}:
1 4 7
2 5 8
3 6 9
Calling SkewSymMatrix
on $M$ is equivalent to doing $M \to \frac{1}{2}(M - M^T)$:
A = SkewSymMatrix(M)
3×3 SkewSymMatrix{Float64, Vector{Float64}}:
0.0 1.0 2.0
-1.0 0.0 1.0
-2.0 -1.0 0.0
And calling SymmetricMatrix
on $M$ is equivalent to doing $M \to \frac{1}{2}(M + M^T)$:
B = SymmetricMatrix(M)
3×3 SymmetricMatrix{Float64, Vector{Float64}}:
1.0 3.0 5.0
3.0 5.0 7.0
5.0 7.0 9.0
We can further confirm the identity above:
M ≈ A + B
true
Note that for LowerTriangular
and UpperTriangular
no projection step is involved, which means that if we start with a matrix of type AbstractMatrix{Int64}
we will end up with a matrix that is also of type AbstractMatrix{Int64}
. The type changes however when we call SkewSymMatrix
and SymmetricMatrix
:
(typeof(A) <: AbstractMatrix{Int64}, typeof(B) <: AbstractMatrix{Int64})
(false, false)
For the triangular matrices:
U = UpperTriangular(M)
L = LowerTriangular(M)
(typeof(U) <: AbstractMatrix{Int64}, typeof(L) <: AbstractMatrix{Int64})
(true, true)
How are Special Matrices Stored?
The following image demonstrates how a skew-symmetric matrix is stored in GeometricMachineLearning
:
So what is stored internally is a vector of size $n(n-1)/2$ for the skew-symmetric matrix and the triangular matrices, and a vector of size $n(n+1)/2$ for the symmetric matrix.
Sample Random Matrices
We can sample a random skew-symmetric matrix:
A = rand(SkewSymMatrix, 3)
3×3 SkewSymMatrix{Float64, Vector{Float64}}:
0.0 -0.521214 -0.586807
0.521214 0.0 -0.890879
0.586807 0.890879 0.0
and then access the vector:
A.S
3-element Vector{Float64}:
0.521213795535383
0.5868067574533484
0.8908786980927811
This is equivalent to sampling a vector and then assigning a matrix[1]:
S = rand(3 * (3 - 1) ÷ 2)
SkewSymMatrix(S, 3)
3×3 SkewSymMatrix{Float64, Vector{Float64}}:
0.0 -0.521214 -0.586807
0.521214 0.0 -0.890879
0.586807 0.890879 0.0
These special matrices are important for SympNets, volume-preserving transformers and linear symplectic transformers.
Parallel Computation
The functions GeometricMachineLearning.mat_tensor_mul
and GeometricMachineLearning.tensor_mat_mul
are also implemented for these matrices for efficient parallel computations. This is elaborated on when we take about tensors.
Library Functions
GeometricMachineLearning.AbstractTriangular
— TypeAbstractTriangular
See UpperTriangular
and LowerTriangular
.
GeometricMachineLearning.UpperTriangular
— TypeUpperTriangular(S::AbstractVector, n::Int)
Build an upper-triangular matrix from a vector.
An upper-triangular matrix is an $n\times{}n$ matrix that has zeros on the diagonal and on the lower triangular.
The data are stored in a vector $S$ similarly to other matrices. See LowerTriangular
, SkewSymMatrix
and SymmetricMatrix
.
The struct two fields: S
and n
. The first stores all the entries of the matrix in a sparse fashion (in a vector) and the second is the dimension $n$ for $A\in\mathbb{R}^{n\times{}n}$.
Examples
using GeometricMachineLearning
S = [1, 2, 3, 4, 5, 6]
UpperTriangular(S, 4)
# output
4×4 UpperTriangular{Int64, Vector{Int64}}:
0 1 2 4
0 0 3 5
0 0 0 6
0 0 0 0
GeometricMachineLearning.UpperTriangular
— MethodUpperTriangular(A::AbstractMatrix)
Build an upper-triangular matrix from a matrix.
This is done by taking the upper right of that matrix.
Examples
using GeometricMachineLearning
M = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
UpperTriangular(M)
# output
4×4 UpperTriangular{Int64, Vector{Int64}}:
0 2 3 4
0 0 7 8
0 0 0 12
0 0 0 0
GeometricMachineLearning.LowerTriangular
— TypeLowerTriangular(S::AbstractVector, n::Int)
Build a lower-triangular matrix from a vector.
A lower-triangular matrix is an $n\times{}n$ matrix that has zeros on the diagonal and on the upper triangular.
The data are stored in a vector $S$ similarly to other matrices. See UpperTriangular
, SkewSymMatrix
and SymmetricMatrix
.
The struct two fields: S
and n
. The first stores all the entries of the matrix in a sparse fashion (in a vector) and the second is the dimension $n$ for $A\in\mathbb{R}^{n\times{}n}$.
Examples
using GeometricMachineLearning
S = [1, 2, 3, 4, 5, 6]
LowerTriangular(S, 4)
# output
4×4 LowerTriangular{Int64, Vector{Int64}}:
0 0 0 0
1 0 0 0
2 3 0 0
4 5 6 0
GeometricMachineLearning.LowerTriangular
— MethodLowerTriangular(A::AbstractMatrix)
Build a lower-triangular matrix from a matrix.
This is done by taking the lower left of that matrix.
Examples
using GeometricMachineLearning
M = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
LowerTriangular(M)
# output
4×4 LowerTriangular{Int64, Vector{Int64}}:
0 0 0 0
5 0 0 0
9 10 0 0
13 14 15 0
Base.vec
— Methodvec(A::AbstractTriangular)
Return the associated vector to $A$.
Examples
using GeometricMachineLearning
M = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
LowerTriangular(M) |> vec
# output
6-element Vector{Int64}:
5
9
10
13
14
15
GeometricMachineLearning.SkewSymMatrix
— TypeSkewSymMatrix(S::AbstractVector, n::Integer)
Instantiate a skew-symmetric matrix with information stored in vector S
.
A skew-symmetric matrix $A$ is a matrix $A^T = -A$.
Internally the struct
saves a vector $S$ of size $n(n-1)\div2$. The conversion is done the following way:
\[[A]_{ij} = \begin{cases} 0 & \text{if $i=j$} \\ S[( (i-2) (i-1) ) \div 2 + j] & \text{if $i>j$}\\ S[( (j-2) (j-1) ) \div 2 + i] & \text{else}. \end{cases}\]
So $S$ stores a string of vectors taken from $A$: $S = [\tilde{a}_1, \tilde{a}_2, \ldots, \tilde{a}_n]$ with $\tilde{a}_i = [[A]_{i1},[A]_{i2},\ldots,[A]_{i(i-1)}]$.
Also see SymmetricMatrix
, LowerTriangular
and UpperTriangular
.
Examples
using GeometricMachineLearning
S = [1, 2, 3, 4, 5, 6]
SkewSymMatrix(S, 4)
# output
4×4 SkewSymMatrix{Int64, Vector{Int64}}:
0 -1 -2 -4
1 0 -3 -5
2 3 0 -6
4 5 6 0
GeometricMachineLearning.SkewSymMatrix
— MethodSkewSymMatrix(A::AbstractMatrix)
Perform 0.5 * (A - A')
and store the matrix in an efficient way (as a vector with $n(n-1)/2$ entries).
If the constructor is called with a matrix as input it returns a skew-symmetric matrix via the projection:
\[A \mapsto \frac{1}{2}(A - A^T).\]
Examples
using GeometricMachineLearning
M = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
SkewSymMatrix(M)
# output
4×4 SkewSymMatrix{Float64, Vector{Float64}}:
0.0 -1.5 -3.0 -4.5
1.5 0.0 -1.5 -3.0
3.0 1.5 0.0 -1.5
4.5 3.0 1.5 0.0
Extended help
Note that the constructor is designed in such a way that it always returns matrices of type SkewSymMatrix{<:AbstractFloat}
when called with a matrix, even if this matrix is of type AbstractMatrix{<:Integer}
.
If the user wishes to allocate a matrix SkewSymMatrix{<:Integer}
then call:
SkewSymMatrix(::AbstractVector, n::Integer)
Note that this is different from LowerTriangular
and UpperTriangular
as no porjection takes place there.
GeometricMachineLearning.SymmetricMatrix
— TypeSymmetricMatrix(S::AbstractVector, n::Integer)
Instantiate a symmetric matrix with information stored in vector S
.
A SymmetricMatrix
$A$ is a matrix $A^T = A$.
Internally the struct
saves a vector $S$ of size $n(n+1)\div2$. The conversion is done the following way:
\[[A]_{ij} = \begin{cases} S[( (i-1) i ) \div 2 + j] & \text{if $i\geq{}j$}\\ S[( (j-1) j ) \div 2 + i] & \text{else}. \end{cases}\]
So $S$ stores a string of vectors taken from $A$: $S = [\tilde{a}_1, \tilde{a}_2, \ldots, \tilde{a}_n]$ with $\tilde{a}_i = [[A]_{i1},[A]_{i2},\ldots,[A]_{ii}]$.
Also see SkewSymMatrix
, LowerTriangular
and UpperTriangular
.
Examples
using GeometricMachineLearning
S = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
SymmetricMatrix(S, 4)
# output
4×4 SymmetricMatrix{Int64, Vector{Int64}}:
1 2 4 7
2 3 5 8
4 5 6 9
7 8 9 10
GeometricMachineLearning.SymmetricMatrix
— MethodSymmetricMatrix(A::AbstractMatrix)
Perform a projection and store the matrix in an efficient way (as a vector with $n(n+1)/2$ entries).
If the constructor is called with a matrix as input it returns a symmetric matrix via the projection:
\[A \mapsto \frac{1}{2}(A + A^T).\]
Examples
using GeometricMachineLearning
M = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
SymmetricMatrix(M)
# output
4×4 SymmetricMatrix{Float64, Vector{Float64}}:
1.0 3.5 6.0 8.5
3.5 6.0 8.5 11.0
6.0 8.5 11.0 13.5
8.5 11.0 13.5 16.0
Extended help
Note that the constructor is designed in such a way that it always returns matrices of type SymmetricMatrix{<:AbstractFloat}
when called with a matrix, even if this matrix is of type AbstractMatrix{<:Integer}
.
If the user wishes to allocate a matrix SymmetricMatrix{<:Integer}
then call
$julia SymmetricMatrix(::AbstractVector, n::Integer)$`
Note that this is different from LowerTriangular
and UpperTriangular
as no porjection takes place there.
Base.vec
— Methodvec(A)
Output the associated vector of A
.
Examples
using GeometricMachineLearning
M = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
SkewSymMatrix(M) |> vec
# output
6-element Vector{Float64}:
1.5
3.0
1.5
4.5
3.0
1.5
- 1We fixed the seed to the same value in both these examples.