Skip to content

Commit cb5f401

Browse files
authored
Generalize lyap and sylvester to abstract matrices (#46545)
1 parent cb0721b commit cb5f401

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

stdlib/LinearAlgebra/src/dense.jl

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,21 +1580,22 @@ julia> X = sylvester(A, B, C)
15801580
-4.46667 1.93333
15811581
3.73333 -1.8
15821582
1583-
julia> A*X + X*B + C
1584-
2×2 Matrix{Float64}:
1585-
2.66454e-15 1.77636e-15
1586-
-3.77476e-15 4.44089e-16
1583+
julia> A*X + X*B ≈ -C
1584+
true
15871585
```
15881586
"""
1589-
function sylvester(A::StridedMatrix{T},B::StridedMatrix{T},C::StridedMatrix{T}) where T<:BlasFloat
1587+
function sylvester(A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix)
1588+
T = promote_type(float(eltype(A)), float(eltype(B)), float(eltype(C)))
1589+
return sylvester(copy_similar(A, T), copy_similar(B, T), copy_similar(C, T))
1590+
end
1591+
function sylvester(A::AbstractMatrix{T}, B::AbstractMatrix{T}, C::AbstractMatrix{T}) where {T<:BlasFloat}
15901592
RA, QA = schur(A)
15911593
RB, QB = schur(B)
1592-
1593-
D = -(adjoint(QA) * (C*QB))
1594-
Y, scale = LAPACK.trsyl!('N','N', RA, RB, D)
1595-
rmul!(QA*(Y * adjoint(QB)), inv(scale))
1594+
D = QA' * C * QB
1595+
D .= .-D
1596+
Y, scale = LAPACK.trsyl!('N', 'N', RA, RB, D)
1597+
rmul!(QA * Y * QB', inv(scale))
15961598
end
1597-
sylvester(A::StridedMatrix{T}, B::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:Integer} = sylvester(float(A), float(B), float(C))
15981599

15991600
Base.@propagate_inbounds function _sylvester_2x1!(A, B, C)
16001601
b = B[1]
@@ -1652,18 +1653,19 @@ julia> X = lyap(A, B)
16521653
0.5 -0.5
16531654
-0.5 0.25
16541655
1655-
julia> A*X + X*A' + B
1656-
2×2 Matrix{Float64}:
1657-
0.0 6.66134e-16
1658-
6.66134e-16 8.88178e-16
1656+
julia> A*X + X*A' ≈ -B
1657+
true
16591658
```
16601659
"""
1661-
function lyap(A::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:BlasFloat}
1660+
function lyap(A::AbstractMatrix, C::AbstractMatrix)
1661+
T = promote_type(float(eltype(A)), float(eltype(C)))
1662+
return lyap(copy_similar(A, T), copy_similar(C, T))
1663+
end
1664+
function lyap(A::AbstractMatrix{T}, C::AbstractMatrix{T}) where {T<:BlasFloat}
16621665
R, Q = schur(A)
1663-
1664-
D = -(adjoint(Q) * (C*Q))
1666+
D = Q' * C * Q
1667+
D .= .-D
16651668
Y, scale = LAPACK.trsyl!('N', T <: Complex ? 'C' : 'T', R, R, D)
1666-
rmul!(Q*(Y * adjoint(Q)), inv(scale))
1669+
rmul!(Q * Y * Q', inv(scale))
16671670
end
1668-
lyap(A::StridedMatrix{T}, C::StridedMatrix{T}) where {T<:Integer} = lyap(float(A), float(C))
16691671
lyap(a::Union{Real,Complex}, c::Union{Real,Complex}) = -c/(2real(a))

stdlib/LinearAlgebra/test/dense.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,20 @@ bimg = randn(n,2)/2
132132
@testset "Lyapunov/Sylvester" begin
133133
x = lyap(a, a2)
134134
@test -a2 a*x + x*a'
135+
y = lyap(a', a2')
136+
@test y lyap(Array(a'), Array(a2'))
137+
@test -a2' a'y + y*a
138+
z = lyap(Tridiagonal(a)', Diagonal(a2))
139+
@test z lyap(Array(Tridiagonal(a)'), Array(Diagonal(a2)))
140+
@test -Diagonal(a2) Tridiagonal(a)'*z + z*Tridiagonal(a)
135141
x2 = sylvester(a[1:3, 1:3], a[4:n, 4:n], a2[1:3,4:n])
136142
@test -a2[1:3, 4:n] a[1:3, 1:3]*x2 + x2*a[4:n, 4:n]
143+
y2 = sylvester(a[1:3, 1:3]', a[4:n, 4:n]', a2[4:n,1:3]')
144+
@test y2 sylvester(Array(a[1:3, 1:3]'), Array(a[4:n, 4:n]'), Array(a2[4:n,1:3]'))
145+
@test -a2[4:n, 1:3]' a[1:3, 1:3]'*y2 + y2*a[4:n, 4:n]'
146+
z2 = sylvester(Tridiagonal(a[1:3, 1:3]), Diagonal(a[4:n, 4:n]), a2[1:3,4:n])
147+
@test z2 sylvester(Array(Tridiagonal(a[1:3, 1:3])), Array(Diagonal(a[4:n, 4:n])), Array(a2[1:3,4:n]))
148+
@test -a2[1:3, 4:n] Tridiagonal(a[1:3, 1:3])*z2 + z2*Diagonal(a[4:n, 4:n])
137149
end
138150

139151
@testset "Matrix square root" begin

0 commit comments

Comments
 (0)