Skip to content

Commit 9d26faf

Browse files
stevengjjishnub
andauthored
add missing methods for division of Hessenberg matrices (#1322)
As noted [on discourse](https://discourse.julialang.org/t/add-a-upperhessenberg-row-in-linearalgebra-factorize/128530/4?u=stevengj), we were missing `/` and `\` methods for `UpperHessenberg` matrices, despite the existence of optimized `ldiv!` and `rdiv!` methods, so it was falling back to slow $O(n^3)$ methods. While I was at it, I also added methods for transpose/adjoint Hessenberg matrices. --------- Co-authored-by: Jishnu Bhattacharya <[email protected]>
1 parent a2d52e1 commit 9d26faf

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/hessenberg.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,29 @@ function \(U::UnitUpperTriangular, H::UpperHessenberg)
177177
UpperHessenberg(HH)
178178
end
179179

180+
function (\)(H::Union{UpperHessenberg,AdjOrTrans{<:Any,<:UpperHessenberg}}, B::AbstractVecOrMat)
181+
TFB = typeof(oneunit(eltype(H)) \ oneunit(eltype(B)))
182+
return ldiv!(H, copy_similar(B, TFB))
183+
end
184+
185+
function (/)(B::AbstractMatrix, H::Union{UpperHessenberg,AdjOrTrans{<:Any,<:UpperHessenberg}})
186+
TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(H)))
187+
return rdiv!(copy_similar(B, TFB), H)
188+
end
189+
190+
ldiv!(H::AdjOrTrans{<:Any,<:UpperHessenberg}, B::AbstractVecOrMat) =
191+
(rdiv!(wrapperop(H)(B), parent(H)); B)
192+
rdiv!(B::AbstractVecOrMat, H::AdjOrTrans{<:Any,<:UpperHessenberg}) =
193+
(ldiv!(parent(H), wrapperop(H)(B)); B)
194+
195+
# fix method ambiguities for right division, from adjtrans.jl:
196+
/(u::AdjointAbsVec, A::UpperHessenberg) = adjoint(adjoint(A) \ u.parent)
197+
/(u::TransposeAbsVec, A::UpperHessenberg) = transpose(transpose(A) \ u.parent)
198+
/(u::AdjointAbsVec, A::Adjoint{<:Any,<:UpperHessenberg}) = adjoint(adjoint(A) \ u.parent)
199+
/(u::TransposeAbsVec, A::Transpose{<:Any,<:UpperHessenberg}) = transpose(transpose(A) \ u.parent)
200+
/(u::AdjointAbsVec, A::Transpose{<:Any,<:UpperHessenberg}) = adjoint(conj(A.parent) \ u.parent) # technically should be adjoint(copy(adjoint(copy(A))) \ u.parent)
201+
/(u::TransposeAbsVec, A::Adjoint{<:Any,<:UpperHessenberg}) = transpose(conj(A.parent) \ u.parent)
202+
180203
# Solving (H+µI)x = b: we can do this in O(m²) time and O(m) memory
181204
# (in-place in x) by the RQ algorithm from:
182205
#

test/hessenberg.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ let n = 10
6666
H = UpperHessenberg(Areal)
6767
@test Array(Hc + H) == Array(Hc) + Array(H)
6868
@test Array(Hc - H) == Array(Hc) - Array(H)
69+
@testset "ldiv and rdiv" begin
70+
for b in (b_, B_), H in (H, Hc, H', Hc', transpose(Hc))
71+
@test H * (H \ b) b
72+
@test (b' / H) * H (Matrix(b') / H) * H b'
73+
@test (transpose(b) / H) * H (Matrix(transpose(b)) / H) * H transpose(b)
74+
end
75+
end
6976
@testset "Preserve UpperHessenberg shape (issue #39388)" begin
7077
H = UpperHessenberg(Areal)
7178
A = rand(n,n)

0 commit comments

Comments
 (0)