Skew-Hermitian eigenproblems
A skew-Hermitian matrix $A = -A^*$ is very special with respect to its eigenvalues/vectors and related properties:
- It has purely imaginary eigenvalues. (If $A$ is real, these come in ± pairs or are zero.)
- We can always find orthonormal eigenvectors ($A$ is normal).
By wrapping a matrix in the SkewHermitian
or SkewHermTridiagonal
types, you can exploit optimized methods for eigenvalue calculations (extending the functions defined in Julia's LinearAlgebra
standard library). Especially for real skew-symmetric $A=-A^T$, these optimized methods are generally much faster than the alternative of forming the complex-Hermitian matrix $iA$, computing its diagonalization, and multiplying the eigenvalues by $-i$.
In particular, optimized methods are provided for eigen
(returning a factorization object storing both eigenvalues and eigenvectors), eigvals
(just eigenvalues), eigvecs
(just eigenvectors), and their in-place variants eigen!
/eigvals!
.
Since the SVD and Schur factorizations can be trivially computed from the eigenvectors/eigenvalues for any normal matrix, we also provide optimized methods for svd
, svdvals
, schur
, and their in-place variants svd!
/svdvals!
/schur!
.
A key intermediate step in solving eigenproblems is computing the Hessenberg tridiagonal reduction of the matrix, and we expose this functionality by providing optimized hessenberg
and hessenberg!
methods for SkewHermitian
matrices as described below. (The Hessenberg tridiagonalization is sometimes useful in its own right for matrix computations.)
Eigenvalues and eigenvectors
The package also provides eigensolvers for SkewHermitian
and SkewHermTridiagonal
matrices. A fast and sparse specialized QR algorithm is implemented for SkewHermTridiagonal
matrices and also for SkewHermitian
matrices using the hessenberg
reduction.
The function eigen
returns a Eigen
structure as the LinearAlgebra standard library:
julia> using SkewLinearAlgebra, LinearAlgebra
julia> A = SkewHermitian([0 2 -7 4; -2 0 -8 3; 7 8 0 1;-4 -3 -1 0]);
julia> E = eigen(A)
Eigen{ComplexF64, ComplexF64, Matrix{ComplexF64}, Vector{ComplexF64}}
values:
4-element Vector{ComplexF64}:
0.0 + 11.934458713974193im
0.0 + 0.7541188264752741im
-0.0 - 0.7541188264752989im
-0.0 - 11.934458713974236im
vectors:
4×4 Matrix{ComplexF64}:
-0.49111+0.0im -0.508735+0.0im 0.508735+0.0im 0.49111+0.0im
-0.488014-0.176712im 0.471107+0.0931315im -0.471107+0.0931315im 0.488014-0.176712im
-0.143534+0.615785im 0.138561-0.284619im -0.138561-0.284619im 0.143534+0.615785im
-0.00717668-0.299303im 0.00692804-0.640561im -0.00692804-0.640561im 0.00717668-0.299303im
The function eigvals
provides the eigenvalues of $A$. The eigenvalues can be sorted and found partially with imaginary part in some given real range or by order.
julia> eigvals(A)
4-element Vector{ComplexF64}:
0.0 + 11.93445871397423im
0.0 + 0.7541188264752853im
-0.0 - 0.7541188264752877im
-0.0 - 11.934458713974225im
julia> eigvals(A,0,15)
2-element Vector{ComplexF64}:
0.0 + 11.93445871397414im
0.0 + 0.7541188264752858im
julia> eigvals(A,1:3)
3-element Vector{ComplexF64}:
0.0 + 11.93445871397423im
0.0 + 0.7541188264752989im
-0.0 - 0.7541188264752758im
SVD
A specialized SVD using the eigenvalue decomposition is implemented for SkewHermitian
and SkewHermTridiagonal
type. These functions can be called using the LinearAlgebra
syntax.
julia> using SkewLinearAlgebra, LinearAlgebra
julia> A = SkewHermitian([0 2 -7 4; -2 0 -8 3; 7 8 0 1;-4 -3 -1 0]);
julia> svd(A)
SVD{ComplexF64, Float64, Matrix{ComplexF64}}
U factor:
4×4 Matrix{ComplexF64}:
0.49111+0.0im -0.49111+0.0im 0.508735+0.0im -0.508735+0.0im
0.488014-0.176712im -0.488014-0.176712im -0.471107+0.0931315im 0.471107+0.0931315im
0.143534+0.615785im -0.143534+0.615785im -0.138561-0.284619im 0.138561-0.284619im
0.00717668-0.299303im -0.00717668-0.299303im -0.00692804-0.640561im 0.00692804-0.640561im
singular values:
4-element Vector{Float64}:
11.93445871397423
11.934458713974193
0.7541188264752989
0.7541188264752758
Vt factor:
4×4 Matrix{ComplexF64}:
0.0-0.49111im 0.176712-0.488014im -0.615785-0.143534im 0.299303-0.00717668im
0.0-0.49111im -0.176712-0.488014im 0.615785-0.143534im -0.299303-0.00717668im
0.0-0.508735im -0.0931315+0.471107im 0.284619+0.138561im 0.640561+0.00692804im
0.0-0.508735im 0.0931315+0.471107im -0.284619+0.138561im -0.640561+0.00692804im
julia> svdvals(A)
4-element Vector{Float64}:
11.93445871397423
11.934458713974225
0.7541188264752877
0.7541188264752853
Hessenberg tridiagonalization
The Hessenberg reduction performs a reduction $A=QHQ^T$ where $Q=\prod_i I-\tau_i v_iv_i^T$ is an orthonormal matrix. The hessenberg
function computes the Hessenberg decomposition of A
and returns a Hessenberg
object. If F
is the factorization object, the unitary matrix can be accessed with F.Q
(of type LinearAlgebra.HessenbergQ
) and the Hessenberg matrix with F.H
(of type SkewHermTridiagonal
), either of which may be converted to a regular matrix with Matrix(F.H)
or Matrix(F.Q)
.
julia> using SkewLinearAlgebra, LinearAlgebra
julia> A = SkewHermitian([0 2 -7 4; -2 0 -8 3; 7 8 0 1;-4 -3 -1 0]);
julia> hessenberg(A)
Hessenberg{Float64, Tridiagonal{Float64, Vector{Float64}}, Matrix{Float64}, Vector{Float64}, Bool}
Q factor:
4×4 LinearAlgebra.HessenbergQ{Float64, Matrix{Float64}, Vector{Float64}, true}:
1.0 0.0 0.0 0.0
0.0 -0.240772 -0.95927 -0.14775
0.0 0.842701 -0.282138 0.458534
0.0 -0.481543 -0.0141069 0.876309
H factor:
4×4 SkewHermTridiagonal{Float64, Vector{Float64}, Nothing}:
0.0 -8.30662 0.0 0.0
8.30662 0.0 -8.53382 0.0
0.0 8.53382 0.0 1.08347
0.0 0.0 -1.08347 0.0