Skew-Hermitian matrices
SkewHermitian(A)
wraps an existing matrix A
, which must already be skew-Hermitian, in the SkewHermitian
type (a subtype of AbstractMatrix
), which supports fast specialized operations noted below. You can use the function isskewhermitian(A)
to check whether A
is skew-Hermitian (A == -A'
).
SkewHermitian(A)
requires that A == -A'
and throws an error if it is not. Alternatively, you can use the funcition skewhermitian(A)
to take the skew-Hermitian part of A
, defined by (A - A')/2
, and wrap it in a SkewHermitian
view. The function skewhermitian!(A)
does the same operation in-place on A
(overwriting A
with its skew-Hermitian part).
Here is a basic example to initialize a SkewHermitian
matrix:
julia> using SkewLinearAlgebra, LinearAlgebra
julia> A = [0 2 -7 4; -2 0 -8 3; 7 8 0 1;-4 -3 -1 0]
3×3 Matrix{Int64}:
0 2 -7 4
-2 0 -8 3
7 8 0 1
-4 -3 -1 0
julia> isskewhermitian(A)
true
julia> A = SkewHermitian(A)
4×4 SkewHermitian{Int64, Matrix{Int64}}:
0 2 -7 4
-2 0 -8 3
7 8 0 1
-4 -3 -1 0
Basic linear-algebra operations are supported:
julia> tr(A)
0
julia> det(A)
81.0
julia> inv(A)
4×4 SkewHermitian{Float64, Matrix{Float64}}:
0.0 0.111111 -0.333333 -0.888889
-0.111111 0.0 0.444444 0.777778
0.333333 -0.444444 0.0 0.222222
0.888889 -0.777778 -0.222222 0.0
julia> x=[1;2;3;4]
4-element Vector{Int64}:
1
2
3
4
julia> A\x
4-element Vector{Float64}:
-4.333333333333334
4.333333333333334
0.3333333333333336
-1.3333333333333333
A SkewHermitian
matrix A
is simply a wrapper around an underlying matrix (in which both the upper and lower triangles are stored, despite the redundancy, to support fast matrix operations). You can extract this underlying matrix with the Julia parent(A)
function (this does not copy the data: mutating the parent will modify A
). Alternatively, you can copy the data to an ordinary Matrix
(2d Array
) with Matrix(A)
.
Operations on SkewHermitian
The SkewHermitian
type supports the basic operations for any Julia AbstractMatrix
(indexing, iteration, multiplication, addition, scaling, and so on). Matrix–matrix and matrix–vector multiplications are performed using the underlying parent matrix, so they are fast.
We try to preserve the SkewHermitian
wrapper, if possible. For example, adding two SkewHermitian
matrices or scaling by a real number yields another SkewHermitian
matrix. Similarly for real(A)
, conj(A)
, inv(A)
, or -A
.
The package provides several optimized methods for SkewHermitian
matrices, based on the functions defined by the Julia LinearAlgebra
package:
- Tridiagonal reduction:
hessenberg
- Eigensolvers:
eigen
,eigvals
(alsoschur
,svd
,svdvals
) - Trigonometric functions:
exp
,cis
,cos
,sin
,sinh
,cosh
,sincos
We also define the following new functions for real skew-symmetric matrices only:
- Cholesky-like factorization:
skewchol
- Pfaffian:
pfaffian
,logabspfaffian
Skew-Hermitian tridiagonal matrices
In the special case of a tridiagonal skew-Hermitian matrix, many calculations can be performed very quickly, typically with $O(n)$ operations for an $n\times n$ matrix. Such optimizations are supported by the SkewLinearAlgebra
package using the SkewHermTridiagonal
matrix type.
A complex tridiagonal skew-Hermitian matrix is of the form:
\[A=\left(\begin{array}{ccccc} id_{1} & -e_{1}^{*}\\ e_{1} & id_{2} & -e_{2}^{*}\\ & e_{2} & id_{3} & \ddots\\ & & \ddots & \ddots & -e_{n-1}^{*}\\ & & & e_{n-1} & id_{n} \end{array}\right)=-A^{*}\]
with purely imaginary diagonal entries $id_k$. This is represented in the SkewLinearAlgebra
package by calling the SkewHermTridiagonal(ev,dvim)
constructor, where ev
is the (complex) vector of $n-1$ subdiagonal entries $e_k$ and dvim
is the (real) vector of $n$ diagonal imaginary parts $d_k$:
julia> SkewHermTridiagonal([1+2im,3+4im],[5,6,7])
3×3 SkewHermTridiagonal{Complex{Int64}, Vector{Complex{Int64}}, Vector{Int64}}:
0+5im -1+2im ⋅
1+2im 0+6im -3+4im
⋅ 3+4im 0+7im
In the case of a real matrix, the diagonal entries are zero, and the matrix takes the form:
\[\text{real }A=\left(\begin{array}{ccccc} 0 & -e_{1}\\ e_{1} & 0 & -e_{2}\\ & e_{2} & 0 & \ddots\\ & & \ddots & \ddots & -e_{n-1}\\ & & & e_{n-1} & 0 \end{array}\right)=-A^{T}\]
In this case, you need not store the zero diagonal entries, and can simply call SkewHermTridiagonal(ev)
with the real vector ev
of the $n-1$ subdiagonal entries:
julia> A = SkewHermTridiagonal([1,2,3])
4×4 SkewHermTridiagonal{Int64, Vector{Int64}, Nothing}:
⋅ -1 ⋅ ⋅
1 ⋅ -2 ⋅
⋅ 2 ⋅ -3
⋅ ⋅ 3 ⋅
(Notice that zero values that are not stored (“structural zeros”) are shown as a ⋅
.)
A SkewHermTridiagonal
matrix can also be converted to the LinearAlgebra.Tridiagonal
type in the Julia standard library:
julia> Tridiagonal(A)
4×4 Tridiagonal{Int64, Vector{Int64}}:
0 -1 ⋅ ⋅
1 0 -2 ⋅
⋅ 2 0 -3
⋅ ⋅ 3 0
which may support a wider range of linear-algebra functions, but does not optimized for the skew-Hermitian structure.
Operations on SkewHermTridiagonal
The SkewHermTridiagonal
type is modeled on the LinearAlgebra.SymTridiagonal
type in the Julia standard library) and supports typical matrix operations (indexing, iteration, scaling, and so on).
The package provides several optimized methods for SkewHermTridiagonal
matrices, based on the functions defined by the Julia LinearAlgebra
package:
- Matrix-vector
A*x
anddot(x,A,y)
products; also solvesA\x
(via conversion toTridiagonal
) - Eigensolvers:
eigen
,eigvals
(alsosvd
,svdvals
) - Trigonometric functions:
exp
,cis
,cos
,sin
,sinh
,cosh
,sincos
Types Reference
SkewLinearAlgebra.SkewHermitian
— TypeSkewHermitian(A) <: AbstractMatrix
Construct a SkewHermitian
view of the skew-Hermitian matrix A
(A == -A'
), which allows one to exploit efficient operations for eigenvalues, exponentiation, and more.
Takes "ownership" of the matrix A
. See also skewhermitian
, which takes the skew-hermitian part of A
, and skewhermitian!
, which does this in-place, along with isskewhermitian
which checks whether A == -A'
.
SkewLinearAlgebra.skewhermitian
— Functionskewhermitian(A)
Returns the skew-Hermitian part of A, i.e. (A-A')/2
. See also skewhermitian!
, which does this in-place.
SkewLinearAlgebra.skewhermitian!
— Functionskewhermitian!(A)
Transforms A
in-place to its skew-Hermitian part (A-A')/2
, and returns a SkewHermitian
view.
SkewLinearAlgebra.SkewHermTridiagonal
— TypeSkewHermTridiagonal(ev::V, dvim::Vim) where {V <: AbstractVector, Vim <: AbstractVector{<:Real}}
Construct a skewhermitian tridiagonal matrix from the subdiagonal (ev
) and the imaginary part of the main diagonal (dvim
). The result is of type SkewHermTridiagonal
and provides efficient specialized eigensolvers, but may be converted into a regular matrix with convert(Array, _)
(or Array(_)
for short).
Examples
julia> ev = complex.([7, 8, 9] , [7, 8, 9])
3-element Vector{Complex{Int64}}:
7 + 7im
8 + 8im
9 + 9im
julia> dvim = [1, 2, 3, 4]
4-element Vector{Int64}:
1
2
3
4
julia> SkewHermTridiagonal(ev, dvim)
4×4 SkewHermTridiagonal{Complex{Int64}, Vector{Complex{Int64}}, Vector{Int64}}:
0+1im -7+7im 0+0im 0+0im
7-7im 0+2im -8+8im 0+0im
0+0im -8+8im 0+3im -9+9im
0+0im 0+0im 9+9im 0+4im
SkewHermTridiagonal(A::AbstractMatrix)
Construct a skewhermitian tridiagonal matrix from first subdiagonal and main diagonal of the skewhermitian matrix A
.
Examples
julia> A = [1 2 3; 2 4 5; 3 5 6]
3×3 Matrix{Int64}:
1 2 3
2 4 5
3 5 6
julia> SkewHermTridiagonal(A)
3×3 SkewHermTridiagonal{Int64, Vector{Int64}}:
0 -2 0
2 0 -5
0 5 0