From fedc3e615b7e3fd5c991fbd539f44afd6a4245af Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 12 Dec 2022 02:32:02 +0100 Subject: [PATCH 1/9] Added hseqr LAPACK function --- stdlib/LinearAlgebra/src/lapack.jl | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 9edaf77440750..51a4fc3793154 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5741,6 +5741,104 @@ for (ormhr, elty) in end end +for (hseqr, elty) in + ((:zhseqr_,:ComplexF64), + (:chseqr_,:ComplexF32)) + @eval begin + # * .. Scalar Arguments .. + # CHARACTER JOB, COMPZ + # INTEGER N, ILO, IHI, LWORK, LDH, LDZ, INFO + # * .. + # * .. Array Arguments .. + # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) + function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, + H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + require_one_based_indexing(H, Z) + chkstride1(H) + n = checksquare(H) + checksquare(Z) == n || throw(DimensionMismatch()) + ldh = max(1, stride(H, 2)) + ldz = max(1, stride(Z, 2)) + w = similar(H, $elty, n) + work = Vector{$elty}(undef, 1) + lwork = BlasInt(-1) + info = Ref{BlasInt}() + for i = 1:2 # first call returns lwork as work[1] + ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, + (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, + Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, + Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, + Ptr{BlasInt}), + job, compz, n, ilo, ihi, + H, ldh, w, Z, ldz, work, + lwork, info) + chklapackerror(info[]) + if i == 1 + lwork = BlasInt(real(work[1])) + resize!(work, lwork) + end + end + H, Z, w + end + end +end + +for (hseqr, elty) in + ((:dhseqr_,:Float64), + (:shseqr_,:Float32)) + @eval begin + # * .. Scalar Arguments .. + # CHARACTER JOB, COMPZ + # INTEGER N, ILO, IHI, LWORK, LDH, LDZ, INFO + # * .. + # * .. Array Arguments .. + # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) + function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, + H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + require_one_based_indexing(H, Z) + chkstride1(H) + n = checksquare(H) + checksquare(Z) == n || throw(DimensionMismatch()) + ldh = max(1, stride(H, 2)) + ldz = max(1, stride(Z, 2)) + wr = similar(H, $elty, n) + wi = similar(H, $elty, n) + work = Vector{$elty}(undef, 1) + lwork = BlasInt(-1) + info = Ref{BlasInt}() + for i = 1:2 # first call returns lwork as work[1] + ccall((@blasfunc($hseqr), libblastrampoline), Cvoid, + (Ref{UInt8}, Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, + Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ptr{$elty}, + Ptr{$elty}, Ref{BlasInt}, Ptr{$elty}, Ref{BlasInt}, + Ptr{BlasInt}), + job, compz, n, ilo, ihi, + H, ldh, wr, wi, Z, ldz, work, + lwork, info) + chklapackerror(info[]) + if i == 1 + lwork = BlasInt(real(work[1])) + resize!(work, lwork) + end + end + H, Z, complex.(wr, wi) + end + end +end +hseqr!(H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) = hseqr!('S', 'V', 1, size(H, 1), H, Z) +hseqr!(H::AbstractMatrix{$elty}) = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) + +""" + hseqr!(job, compz, ilo, ihi, H, Z) -> (H, Z, w) + +Computes all eigenvalues and (optionally) the Schur factorization of a matrix +reduced to Hessenberg form. If `H` is balanced with `gebal!` +then `ilo` and `ihi` are the outputs of `gebal!`. Otherwise they should be +`ilo = 1` and `ihi = size(H,2)`. `tau` contains the elementary reflectors of +the factorization. +""" +hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) + for (hetrd, elty) in ((:dsytrd_,Float64), (:ssytrd_,Float32), From 2dbd862f07a1cfa13b0f09019cce3ce3c1df48b7 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 12 Dec 2022 02:52:50 +0100 Subject: [PATCH 2/9] Fix eltype problem --- stdlib/LinearAlgebra/src/lapack.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 51a4fc3793154..54b6355b4725a 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5825,8 +5825,8 @@ for (hseqr, elty) in end end end -hseqr!(H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) = hseqr!('S', 'V', 1, size(H, 1), H, Z) -hseqr!(H::AbstractMatrix{$elty}) = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) +hseqr!(H::AbstractMatrix, Z::AbstractMatrix) = hseqr!('S', 'V', 1, size(H, 1), H, Z) +hseqr!(H::AbstractMatrix) = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) """ hseqr!(job, compz, ilo, ihi, H, Z) -> (H, Z, w) From 017748aad77f427e4ebf60a107dc760237bf1f84 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 12 Dec 2022 03:00:27 +0100 Subject: [PATCH 3/9] Fix eltype problem --- stdlib/LinearAlgebra/src/lapack.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 54b6355b4725a..9da6d7bfd5995 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5837,7 +5837,7 @@ then `ilo` and `ihi` are the outputs of `gebal!`. Otherwise they should be `ilo = 1` and `ihi = size(H,2)`. `tau` contains the elementary reflectors of the factorization. """ -hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) +hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, H::AbstractMatrix, Z::AbstractMatrix) for (hetrd, elty) in ((:dsytrd_,Float64), From be6b77ff0ac95355fd8a825b2510060f480a42b6 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 12 Dec 2022 03:21:23 +0100 Subject: [PATCH 4/9] Fixed Whitespaces --- stdlib/LinearAlgebra/src/lapack.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 9da6d7bfd5995..d77d2c435503a 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5751,7 +5751,7 @@ for (hseqr, elty) in # * .. # * .. Array Arguments .. # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) - function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, + function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) require_one_based_indexing(H, Z) chkstride1(H) @@ -5793,7 +5793,7 @@ for (hseqr, elty) in # * .. # * .. Array Arguments .. # COMPLEX*16 H( LDH, * ), Z( LDZ, * ), WORK( * ) - function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, + function hseqr!(job::AbstractChar, compz::AbstractChar, ilo::Integer, ihi::Integer, H::AbstractMatrix{$elty}, Z::AbstractMatrix{$elty}) require_one_based_indexing(H, Z) chkstride1(H) @@ -5831,7 +5831,7 @@ hseqr!(H::AbstractMatrix) = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) """ hseqr!(job, compz, ilo, ihi, H, Z) -> (H, Z, w) -Computes all eigenvalues and (optionally) the Schur factorization of a matrix +Computes all eigenvalues and (optionally) the Schur factorization of a matrix reduced to Hessenberg form. If `H` is balanced with `gebal!` then `ilo` and `ihi` are the outputs of `gebal!`. Otherwise they should be `ilo = 1` and `ihi = size(H,2)`. `tau` contains the elementary reflectors of From 266c05e75863521bd4b8c2d8ba5ed44e62bba9cd Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Mon, 12 Dec 2022 10:08:19 +0100 Subject: [PATCH 5/9] Added API documentation --- stdlib/LinearAlgebra/docs/src/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/LinearAlgebra/docs/src/index.md b/stdlib/LinearAlgebra/docs/src/index.md index a95b622480191..9f12af174a4ff 100644 --- a/stdlib/LinearAlgebra/docs/src/index.md +++ b/stdlib/LinearAlgebra/docs/src/index.md @@ -745,6 +745,7 @@ LinearAlgebra.LAPACK.trexc! LinearAlgebra.LAPACK.trsen! LinearAlgebra.LAPACK.tgsen! LinearAlgebra.LAPACK.trsyl! +LinearAlgebra.LAPACK.hseqr! ``` ```@meta From 4cc8e07a91045616bf8b173d0005de1017c9ba2a Mon Sep 17 00:00:00 2001 From: Alberto Mercurio <61953577+albertomercurio@users.noreply.github.com> Date: Tue, 13 Dec 2022 01:35:52 +0100 Subject: [PATCH 6/9] Update stdlib/LinearAlgebra/src/lapack.jl Co-authored-by: Daniel Karrasch --- stdlib/LinearAlgebra/src/lapack.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index d77d2c435503a..b49b1be1ec503 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5825,8 +5825,8 @@ for (hseqr, elty) in end end end -hseqr!(H::AbstractMatrix, Z::AbstractMatrix) = hseqr!('S', 'V', 1, size(H, 1), H, Z) -hseqr!(H::AbstractMatrix) = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) +hseqr!(H::StridedMatrix{T}, Z::AbstractMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) +hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) """ hseqr!(job, compz, ilo, ihi, H, Z) -> (H, Z, w) From cec820a3ea3f682ebf27ab17c166f81f5e745afa Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 13 Dec 2022 08:35:42 +0100 Subject: [PATCH 7/9] Added schur function and test --- stdlib/LinearAlgebra/src/lapack.jl | 2 +- stdlib/LinearAlgebra/src/schur.jl | 3 +++ stdlib/LinearAlgebra/test/schur.jl | 9 +++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index b49b1be1ec503..d9604d3f79b75 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5826,7 +5826,7 @@ for (hseqr, elty) in end end hseqr!(H::StridedMatrix{T}, Z::AbstractMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) -hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, one(H)) +hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) """ hseqr!(job, compz, ilo, ihi, H, Z) -> (H, Z, w) diff --git a/stdlib/LinearAlgebra/src/schur.jl b/stdlib/LinearAlgebra/src/schur.jl index 98ba9b22bb478..2b4c32f174bce 100644 --- a/stdlib/LinearAlgebra/src/schur.jl +++ b/stdlib/LinearAlgebra/src/schur.jl @@ -102,6 +102,8 @@ julia> A """ schur!(A::StridedMatrix{<:BlasFloat}) = Schur(LinearAlgebra.LAPACK.gees!('V', A)...) +schur!(A::UpperHessenberg{T}) where {T<:BlasFloat} = Schur(LinearAlgebra.LAPACK.hseqr!(parent(A))...) + """ schur(A) -> F::Schur @@ -153,6 +155,7 @@ true ``` """ schur(A::AbstractMatrix{T}) where {T} = schur!(copy_similar(A, eigtype(T))) +schur(A::UpperHessenberg{T}) where {T<:BlasFloat} = schur!(copy_similar(A, eigtype(T))) function schur(A::RealHermSymComplexHerm) F = eigen(A; sortby=nothing) return Schur(typeof(F.vectors)(Diagonal(F.values)), F.vectors, F.values) diff --git a/stdlib/LinearAlgebra/test/schur.jl b/stdlib/LinearAlgebra/test/schur.jl index d047ca12abc1f..c267ffd43955e 100644 --- a/stdlib/LinearAlgebra/test/schur.jl +++ b/stdlib/LinearAlgebra/test/schur.jl @@ -202,4 +202,13 @@ end @test A' ≈ C ≈ E end +@testset "UpperHessenberg schur" begin + A = UpperHessenberg(rand(ComplexF64, 100, 100)) + B = Array(A) + fact1 = schur(A) + fact2 = schur(B) + @test fact1.values ≈ fact2.values + @test fact1.Z * fact1.T * fact1.Z' ≈ A +end + end # module TestSchur From efd0321997d262ddbb1b0effd027905052ae1896 Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Tue, 13 Dec 2022 11:54:33 +0100 Subject: [PATCH 8/9] Minor changes --- stdlib/LinearAlgebra/src/lapack.jl | 2 +- stdlib/LinearAlgebra/src/schur.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index d9604d3f79b75..82ce01fd8428b 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5825,7 +5825,7 @@ for (hseqr, elty) in end end end -hseqr!(H::StridedMatrix{T}, Z::AbstractMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) +hseqr!(H::StridedMatrix{T}, Z::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'V', 1, size(H, 1), H, Z) hseqr!(H::StridedMatrix{T}) where {T<:BlasFloat} = hseqr!('S', 'I', 1, size(H, 1), H, similar(H)) """ diff --git a/stdlib/LinearAlgebra/src/schur.jl b/stdlib/LinearAlgebra/src/schur.jl index 2b4c32f174bce..53741adb48cf9 100644 --- a/stdlib/LinearAlgebra/src/schur.jl +++ b/stdlib/LinearAlgebra/src/schur.jl @@ -155,7 +155,7 @@ true ``` """ schur(A::AbstractMatrix{T}) where {T} = schur!(copy_similar(A, eigtype(T))) -schur(A::UpperHessenberg{T}) where {T<:BlasFloat} = schur!(copy_similar(A, eigtype(T))) +schur(A::UpperHessenberg{T}) where {T} = schur!(copy_similar(A, eigtype(T))) function schur(A::RealHermSymComplexHerm) F = eigen(A; sortby=nothing) return Schur(typeof(F.vectors)(Diagonal(F.values)), F.vectors, F.values) From 304520054577d80f68daa5f551177774d0825dfb Mon Sep 17 00:00:00 2001 From: Alberto Mercurio Date: Wed, 14 Dec 2022 14:34:17 +0100 Subject: [PATCH 9/9] Added test with Int matrix --- stdlib/LinearAlgebra/test/schur.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/test/schur.jl b/stdlib/LinearAlgebra/test/schur.jl index c267ffd43955e..c9a5d92dbdae8 100644 --- a/stdlib/LinearAlgebra/test/schur.jl +++ b/stdlib/LinearAlgebra/test/schur.jl @@ -208,7 +208,14 @@ end fact1 = schur(A) fact2 = schur(B) @test fact1.values ≈ fact2.values - @test fact1.Z * fact1.T * fact1.Z' ≈ A + @test fact1.Z * fact1.T * fact1.Z' ≈ B + + A = UpperHessenberg(rand(Int32, 50, 50)) + B = Array(A) + fact1 = schur(A) + fact2 = schur(B) + @test fact1.values ≈ fact2.values + @test fact1.Z * fact1.T * fact1.Z' ≈ B end end # module TestSchur