Skip to content

Commit 5334abd

Browse files
authored
Differentiation of eigen(::Symmetric) (#575)
1 parent 452b37b commit 5334abd

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

src/dual.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,12 @@ function LinearAlgebra.eigvals(A::Symmetric{<:Dual{Tg,T,N}}) where {Tg,T<:Real,N
706706
Dual{Tg}.(λ, tuple.(parts...))
707707
end
708708

709+
function LinearAlgebra.eigvals(A::Symmetric{<:Dual{Tg,T,N}, <:StaticArrays.StaticMatrix}) where {Tg,T<:Real,N}
710+
λ,Q = eigen(Symmetric(value.(parent(A))))
711+
parts = ntuple(j -> diag(Q' * getindex.(partials.(A), j) * Q), N)
712+
Dual{Tg}.(λ, tuple.(parts...))
713+
end
714+
709715
function LinearAlgebra.eigvals(A::Hermitian{<:Complex{<:Dual{Tg,T,N}}}) where {Tg,T<:Real,N}
710716
λ,Q = eigen(Hermitian(value.(real.(parent(A))) .+ im .* value.(imag.(parent(A)))))
711717
parts = ntuple(j -> diag(real.(Q' * (getindex.(partials.(real.(A)) .+ im .* partials.(imag.(A)), j)) * Q)), N)
@@ -730,7 +736,14 @@ end
730736

731737
function LinearAlgebra.eigen(A::Symmetric{<:Dual{Tg,T,N}}) where {Tg,T<:Real,N}
732738
λ = eigvals(A)
733-
_,Q = eigen(SymTridiagonal(value.(parent(A).dv),value.(parent(A).ev)))
739+
_,Q = eigen(Symmetric(value.(parent(A))))
740+
parts = ntuple(j -> Q*_lyap_div!(Q' * getindex.(partials.(A), j) * Q - Diagonal(getindex.(partials.(λ), j)), value.(λ)), N)
741+
Eigen(λ,Dual{Tg}.(Q, tuple.(parts...)))
742+
end
743+
744+
function LinearAlgebra.eigen(A::Symmetric{<:Dual{Tg,T,N}, <:StaticArrays.StaticMatrix}) where {Tg,T<:Real,N}
745+
λ = eigvals(A)
746+
_,Q = eigen(Symmetric(value.(parent(A))))
734747
parts = ntuple(j -> Q*_lyap_div!(Q' * getindex.(partials.(A), j) * Q - Diagonal(getindex.(partials.(λ), j)), value.(λ)), N)
735748
Eigen(λ,Dual{Tg}.(Q, tuple.(parts...)))
736749
end

test/JacobianTest.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,14 @@ end
235235
@testset "eigen" begin
236236
@test ForwardDiff.jacobian(x -> eigvals(SymTridiagonal(x, x[1:end-1])), [1.,2.]) [(1 - 3/sqrt(5))/2 (1 - 1/sqrt(5))/2 ; (1 + 3/sqrt(5))/2 (1 + 1/sqrt(5))/2]
237237
@test ForwardDiff.jacobian(x -> eigvals(Symmetric(x*x')), [1.,2.]) [0 0; 2 4]
238+
239+
x0 = [1.0, 2.0];
240+
ev1(x) = eigen(Symmetric(x*x')).vectors[:,1]
241+
@test ForwardDiff.jacobian(ev1, x0) Calculus.finite_difference_jacobian(ev1, x0)
242+
ev2(x) = eigen(SymTridiagonal(x, x[1:end-1])).vectors[:,1]
243+
@test ForwardDiff.jacobian(ev2, x0) Calculus.finite_difference_jacobian(ev2, x0)
244+
x0_static = SVector{2}(x0)
245+
@test ForwardDiff.jacobian(ev1, x0_static) Calculus.finite_difference_jacobian(ev1, x0)
238246
end
239247

240248
@testset "type stability" begin

0 commit comments

Comments
 (0)