Skip to content

Commit dc72139

Browse files
authored
switch Hessenberg types to standard LinearAlgebra ones (#172)
* switch Hessenberg types to standard LinearAlgebra ones * remove piracy * add test * add piracy back (otherwise we have trouble with LinearAlgebra) * Hessenberg is not an AbstractMatrix * needed to actually use the Hessenberg methods * fix julia 1.6
1 parent e7520a6 commit dc72139

File tree

2 files changed

+17
-71
lines changed

2 files changed

+17
-71
lines changed

src/eigenGeneral.jl

Lines changed: 12 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,75 +2,34 @@ using Printf
22
using LinearAlgebra
33
using LinearAlgebra: Givens, Rotation, givens
44

5-
import Base: \
6-
7-
# Hessenberg Matrix
8-
struct HessenbergMatrix{T,S<:StridedMatrix} <: AbstractMatrix{T}
9-
data::S
10-
end
11-
12-
Base.copy(H::HessenbergMatrix{T,S}) where {T,S} = HessenbergMatrix{T,S}(copy(H.data))
13-
14-
Base.getindex(H::HessenbergMatrix{T,S}, i::Integer, j::Integer) where {T,S} =
15-
i > j + 1 ? zero(T) : H.data[i, j]
16-
17-
Base.size(H::HessenbergMatrix) = size(H.data)
18-
Base.size(H::HessenbergMatrix, i::Integer) = size(H.data, i)
19-
20-
function LinearAlgebra.ldiv!(H::HessenbergMatrix, B::AbstractVecOrMat)
21-
n = size(H, 1)
22-
Hd = H.data
23-
for i = 1:n-1
24-
G, _ = givens(Hd, i, i + 1, i)
25-
lmul!(G, view(Hd, 1:n, i:n))
26-
lmul!(G, B)
27-
end
28-
ldiv!(UpperTriangular(Hd), B)
29-
end
30-
(\)(H::HessenbergMatrix, B::AbstractVecOrMat) = ldiv!(copy(H), copy(B))
31-
325
if VERSION < v"1.10"
336
# ensure tests pass on Julia v1.6
347
copy_similar(A::AbstractArray, ::Type{T}) where {T} = copyto!(similar(A, T, size(A)), A)
358
eigtype(T) = promote_type(Float32, typeof(zero(T)/sqrt(abs2(one(T)))))
369
eigencopy_oftype(A, S) = copy_similar(A, S)
37-
LinearAlgebra.eigvals(A::HessenbergMatrix{T}; kws...) where T = LinearAlgebra.eigvals!(eigencopy_oftype(A, eigtype(T)); kws...)
10+
LinearAlgebra.eigvals(A::UpperHessenberg{T}; kws...) where T = LinearAlgebra.eigvals!(eigencopy_oftype(A, eigtype(T)); kws...)
11+
Base.:\(H::UpperHessenberg, B::AbstractVecOrMat) = ldiv!(copy(H), copy(B))
3812
end
39-
40-
# Hessenberg factorization
41-
struct HessenbergFactorization{T,S<:StridedMatrix,U} <: Factorization{T}
42-
data::S
43-
τ::Vector{U}
13+
if v"1.10" VERSION < v"1.14"
14+
#otherwise the Hessenberg shortcut is not used
15+
LinearAlgebra.eigencopy_oftype(H::UpperHessenberg, S) = UpperHessenberg(LinearAlgebra.eigencopy_oftype(H.data, S))
4416
end
4517

46-
Base.copy(HF::HessenbergFactorization{T,S,U}) where {T,S,U} =
47-
HessenbergFactorization{T,S,U}(copy(HF.data), copy(HF.τ))
48-
4918
function _hessenberg!(A::StridedMatrix{T}) where {T}
5019
n = LinearAlgebra.checksquare(A)
51-
τ = Vector{Householder{T}}(undef, n - 1)
20+
τ = Vector{T}(undef, n - 1)
5221
for i = 1:n-1
5322
xi = view(A, i+1:n, i)
5423
t = LinearAlgebra.reflector!(xi)
24+
τ[i] = t
5525
H = Householder{T,typeof(xi)}(view(xi, 2:n-i), t)
56-
τ[i] = H
5726
lmul!(H', view(A, i+1:n, i+1:n))
5827
rmul!(view(A, :, i+1:n), H)
5928
end
60-
return HessenbergFactorization{T,typeof(A),eltype(τ)}(A, τ)
29+
return Hessenberg(A, τ)
6130
end
6231
LinearAlgebra.hessenberg!(A::StridedMatrix) = _hessenberg!(A)
6332

64-
Base.size(H::HessenbergFactorization, args...) = size(H.data, args...)
65-
66-
function Base.getproperty(F::HessenbergFactorization, s::Symbol)
67-
if s === :H
68-
return HessenbergMatrix{eltype(F.data),typeof(F.data)}(F.data)
69-
else
70-
return getfield(F, s)
71-
end
72-
end
73-
7433
# Schur
7534
struct Schur{T,S<:StridedMatrix} <: Factorization{T}
7635
data::S
@@ -87,12 +46,11 @@ end
8746

8847
# We currently absorb extra unsupported keywords in kwargs. These could e.g. be scale and permute. Do we want to check that these are false?
8948
function _schur!(
90-
H::HessenbergFactorization{T};
49+
H::UpperHessenberg{T};
9150
tol = eps(real(T)),
9251
shiftmethod = :Francis,
9352
maxiter = 30 * size(H, 1),
9453
) where {T}
95-
9654
n = size(H, 1)
9755
istart = 1
9856
iend = n
@@ -179,7 +137,7 @@ function _schur!(
179137

180138
return Schur{T,typeof(HH)}(HH, τ)
181139
end
182-
_schur!(A::StridedMatrix; kwargs...) = _schur!(_hessenberg!(A); kwargs...)
140+
_schur!(A::StridedMatrix; kwargs...) = _schur!(_hessenberg!(A).H; kwargs...)
183141

184142
# FIXME! Move this method to piracy extension
185143
LinearAlgebra.schur!(A::StridedMatrix; kwargs...) = _schur!(A; kwargs...)
@@ -279,29 +237,21 @@ function doubleShiftQR!(
279237
end
280238

281239
_eigvals!(A::StridedMatrix; kwargs...) = _eigvals!(_schur!(A; kwargs...))
282-
_eigvals!(H::HessenbergMatrix; kwargs...) = _eigvals!(_schur!(H; kwargs...))
283-
_eigvals!(H::HessenbergFactorization; kwargs...) = _eigvals!(_schur!(H; kwargs...))
240+
_eigvals!(H::UpperHessenberg; kwargs...) = _eigvals!(_schur!(H; kwargs...))
284241

285242
function LinearAlgebra.eigvals!(
286243
A::StridedMatrix;
287244
sortby::Union{Function,Nothing} = LinearAlgebra.eigsortby,
288245
kwargs...,
289246
)
290-
291247
if ishermitian(A)
292248
return LinearAlgebra.sorteig!(eigvals!(Hermitian(A)), sortby)
293249
end
294250
LinearAlgebra.sorteig!(_eigvals!(A; kwargs...), sortby)
295251
end
296252

297253
LinearAlgebra.eigvals!(
298-
H::HessenbergMatrix;
299-
sortby::Union{Function,Nothing} = LinearAlgebra.eigsortby,
300-
kwargs...,
301-
) = LinearAlgebra.sorteig!(_eigvals!(H; kwargs...), sortby)
302-
303-
LinearAlgebra.eigvals!(
304-
H::HessenbergFactorization;
254+
H::UpperHessenberg;
305255
sortby::Union{Function,Nothing} = LinearAlgebra.eigsortby,
306256
kwargs...,
307257
) = LinearAlgebra.sorteig!(_eigvals!(H; kwargs...), sortby)

test/eigengeneral.jl

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -239,16 +239,12 @@ using Test, GenericLinearAlgebra, LinearAlgebra
239239
@testset "_hessenberg! and Hessenberg" begin
240240
n = 10
241241
A = randn(n, n)
242-
HF = GenericLinearAlgebra._hessenberg!(copy(A))
243-
for i = 1:length(HF.τ)
244-
HM = convert(Matrix, HF.τ[i])
245-
A[(i+1):end, :] = HM * A[(i+1):end, :]
246-
A[:, (i+1):end] = A[:, (i+1):end] * HM'
247-
end
242+
HF = hessenberg(big.(A))
243+
LHF = hessenberg(A)
244+
@test Matrix(HF) Matrix(LHF)
245+
A = HF.Q' * A * HF.Q
248246
@test tril(A, -2) zeros(n, n) atol = 1e-14
249-
250-
@test eigvals(HF.H) eigvals(A)
251-
@test eigvals(HF.H) eigvals!(copy(HF))
247+
@test eigvals(HF.H) eigvals(LHF.H) eigvals(A)
252248
@test HF.H \ ones(n) Matrix(HF.H) \ ones(n)
253249
end
254250
end

0 commit comments

Comments
 (0)