11# This file is a part of Julia. License is MIT: https://julialang.org/license
22
3+ # preserve HermOrSym wrapper
4+ eigencopy_oftype (A:: Hermitian , S) = Hermitian (copy_similar (A, S), sym_uplo (A. uplo))
5+ eigencopy_oftype (A:: Symmetric , S) = Symmetric (copy_similar (A, S), sym_uplo (A. uplo))
6+
37# Eigensolvers for symmetric and Hermitian matrices
48eigen! (A:: RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix} ; sortby:: Union{Function,Nothing} = nothing ) =
59 Eigen (sorteig! (LAPACK. syevr! (' V' , ' A' , A. uplo, A. data, 0.0 , 0.0 , 0 , 0 , - 1.0 )... , sortby)... )
610
711function eigen (A:: RealHermSymComplexHerm ; sortby:: Union{Function,Nothing} = nothing )
8- T = eltype (A)
9- S = eigtype (T)
10- eigen! (S != T ? convert (AbstractMatrix{S}, A) : copy (A), sortby= sortby)
12+ S = eigtype (eltype (A))
13+ eigen! (eigencopy_oftype (A, S), sortby= sortby)
1114end
1215
1316eigen! (A:: RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix} , irange:: UnitRange ) =
@@ -31,9 +34,8 @@ The [`UnitRange`](@ref) `irange` specifies indices of the sorted eigenvalues to
3134 will be a *truncated* factorization.
3235"""
3336function eigen (A:: RealHermSymComplexHerm , irange:: UnitRange )
34- T = eltype (A)
35- S = eigtype (T)
36- eigen! (S != T ? convert (AbstractMatrix{S}, A) : copy (A), irange)
37+ S = eigtype (eltype (A))
38+ eigen! (eigencopy_oftype (A, S), irange)
3739end
3840
3941eigen! (A:: RealHermSymComplexHerm{T,<:StridedMatrix} , vl:: Real , vh:: Real ) where {T<: BlasReal } =
@@ -57,9 +59,8 @@ The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`
5759 will be a *truncated* factorization.
5860"""
5961function eigen (A:: RealHermSymComplexHerm , vl:: Real , vh:: Real )
60- T = eltype (A)
61- S = eigtype (T)
62- eigen! (S != T ? convert (AbstractMatrix{S}, A) : copy (A), vl, vh)
62+ S = eigtype (eltype (A))
63+ eigen! (eigencopy_oftype (A, S), vl, vh)
6364end
6465
6566function eigvals! (A:: RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix} ; sortby:: Union{Function,Nothing} = nothing )
@@ -69,9 +70,8 @@ function eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}; sortby:
6970end
7071
7172function eigvals (A:: RealHermSymComplexHerm ; sortby:: Union{Function,Nothing} = nothing )
72- T = eltype (A)
73- S = eigtype (T)
74- eigvals! (S != T ? convert (AbstractMatrix{S}, A) : copy (A), sortby= sortby)
73+ S = eigtype (eltype (A))
74+ eigvals! (eigencopy_oftype (A, S), sortby= sortby)
7575end
7676
7777"""
@@ -110,9 +110,8 @@ julia> eigvals(A)
110110```
111111"""
112112function eigvals (A:: RealHermSymComplexHerm , irange:: UnitRange )
113- T = eltype (A)
114- S = eigtype (T)
115- eigvals! (S != T ? convert (AbstractMatrix{S}, A) : copy (A), irange)
113+ S = eigtype (eltype (A))
114+ eigvals! (eigencopy_oftype (A, S), irange)
116115end
117116
118117"""
@@ -150,9 +149,8 @@ julia> eigvals(A)
150149```
151150"""
152151function eigvals (A:: RealHermSymComplexHerm , vl:: Real , vh:: Real )
153- T = eltype (A)
154- S = eigtype (T)
155- eigvals! (S != T ? convert (AbstractMatrix{S}, A) : copy (A), vl, vh)
152+ S = eigtype (eltype (A))
153+ eigvals! (eigencopy_oftype (A, S), vl, vh)
156154end
157155
158156eigmax (A:: RealHermSymComplexHerm{<:Real,<:StridedMatrix} ) = eigvals (A, size (A, 1 ): size (A, 1 ))[1 ]
@@ -166,107 +164,25 @@ function eigen!(A::Hermitian{T,S}, B::Hermitian{T,S}; sortby::Union{Function,Not
166164 vals, vecs, _ = LAPACK. sygvd! (1 , ' V' , A. uplo, A. data, B. uplo == A. uplo ? B. data : copy (B. data' ))
167165 GeneralizedEigen (sorteig! (vals, vecs, sortby)... )
168166end
169-
170167function eigen! (A:: RealHermSymComplexHerm{T,S} , B:: AbstractMatrix{T} ; sortby:: Union{Function,Nothing} = nothing ) where {T<: Number ,S<: StridedMatrix }
168+ return _choleigen! (A, B, sortby)
169+ end
170+ function eigen! (A:: StridedMatrix{T} , B:: Union{RealHermSymComplexHerm{T},Diagonal{T}} ; sortby:: Union{Function,Nothing} = nothing ) where {T<: Number }
171+ return _choleigen! (A, B, sortby)
172+ end
173+ function _choleigen! (A, B, sortby)
171174 U = cholesky (B). U
172175 vals, w = eigen! (UtiAUi! (A, U))
173176 vecs = U \ w
174177 GeneralizedEigen (sorteig! (vals, vecs, sortby)... )
175178end
176179
177- # Perform U' \ A / U in-place.
178- UtiAUi! (As:: Symmetric , Utr:: UpperTriangular ) = Symmetric (_UtiAsymUi! (As. uplo, parent (As), parent (Utr)), sym_uplo (As. uplo))
179- UtiAUi! (As:: Hermitian , Utr:: UpperTriangular ) = Hermitian (_UtiAsymUi! (As. uplo, parent (As), parent (Utr)), sym_uplo (As. uplo))
180- UtiAUi! (As:: Symmetric , Udi:: Diagonal ) = Symmetric (_UtiAsymUi_diag! (As. uplo, parent (As), Udi), sym_uplo (As. uplo))
181- UtiAUi! (As:: Hermitian , Udi:: Diagonal ) = Hermitian (_UtiAsymUi_diag! (As. uplo, parent (As), Udi), sym_uplo (As. uplo))
182-
183- # U is upper triangular
184- function _UtiAsymUi! (uplo, A, U)
185- n = size (A, 1 )
186- μ⁻¹ = 1 / U[1 , 1 ]
187- αμ⁻² = A[1 , 1 ] * μ⁻¹' * μ⁻¹
188-
189- # Update (1, 1) element
190- A[1 , 1 ] = αμ⁻²
191- if n > 1
192- Unext = view (U, 2 : n, 2 : n)
193-
194- if uplo === ' U'
195- # Update submatrix
196- for j in 2 : n, i in 2 : j
197- A[i, j] = (
198- A[i, j]
199- - μ⁻¹' * U[1 , j] * A[1 , i]'
200- - μ⁻¹ * A[1 , j] * U[1 , i]'
201- + αμ⁻² * U[1 , j] * U[1 , i]'
202- )
203- end
204-
205- # Update vector
206- for j in 2 : n
207- A[1 , j] = A[1 , j] * μ⁻¹' - U[1 , j] * αμ⁻²
208- end
209- ldiv! (view (A' , 2 : n, 1 ), UpperTriangular (Unext)' , view (A' , 2 : n, 1 ))
210- else
211- # Update submatrix
212- for j in 2 : n, i in 2 : j
213- A[j, i] = (
214- A[j, i]
215- - μ⁻¹ * A[i, 1 ]' * U[1 , j]'
216- - μ⁻¹' * U[1 , i] * A[j, 1 ]
217- + αμ⁻² * U[1 , i] * U[1 , j]'
218- )
219- end
220-
221- # Update vector
222- for j in 2 : n
223- A[j, 1 ] = A[j, 1 ] * μ⁻¹ - U[1 , j]' * αμ⁻²
224- end
225- ldiv! (view (A, 2 : n, 1 ), UpperTriangular (Unext)' , view (A, 2 : n, 1 ))
226- end
227-
228- # Recurse
229- _UtiAsymUi! (uplo, view (A, 2 : n, 2 : n), Unext)
230- end
231-
232- return A
233- end
180+ # Perform U' \ A / U in-place, where U::Union{UpperTriangular,Diagonal}
181+ UtiAUi! (A:: StridedMatrix , U) = _UtiAUi! (A, U)
182+ UtiAUi! (A:: Symmetric , U) = Symmetric (_UtiAUi! (copytri! (parent (A), A. uplo), U), sym_uplo (A. uplo))
183+ UtiAUi! (A:: Hermitian , U) = Hermitian (_UtiAUi! (copytri! (parent (A), A. uplo, true ), U), sym_uplo (A. uplo))
234184
235- # U is diagonal
236- function _UtiAsymUi_diag! (uplo, A, U)
237- n = size (A, 1 )
238- μ⁻¹ = 1 / U[1 , 1 ]
239- αμ⁻² = A[1 , 1 ] * μ⁻¹' * μ⁻¹
240-
241- # Update (1, 1) element
242- A[1 , 1 ] = αμ⁻²
243- if n > 1
244- Unext = view (U, 2 : n, 2 : n)
245-
246- if uplo === ' U'
247- # No need to update any submatrix when U is diagonal
248-
249- # Update vector
250- for j in 2 : n
251- A[1 , j] = A[1 , j] * μ⁻¹'
252- end
253- ldiv! (view (A' , 2 : n, 1 ), Diagonal (Unext)' , view (A' , 2 : n, 1 ))
254- else
255- # No need to update any submatrix when U is diagonal
256-
257- # Update vector
258- for j in 2 : n
259- A[j, 1 ] = A[j, 1 ] * μ⁻¹
260- end
261- ldiv! (view (A, 2 : n, 1 ), Diagonal (Unext)' , view (A, 2 : n, 1 ))
262- end
263-
264- # Recurse
265- _UtiAsymUi! (uplo, view (A, 2 : n, 2 : n), Unext)
266- end
267-
268- return A
269- end
185+ _UtiAUi! (A, U) = rdiv! (ldiv! (U' , A), U)
270186
271187function eigvals! (A:: HermOrSym{T,S} , B:: HermOrSym{T,S} ; sortby:: Union{Function,Nothing} = nothing ) where {T<: BlasReal ,S<: StridedMatrix }
272188 vals = LAPACK. sygvd! (1 , ' N' , A. uplo, A. data, B. uplo == A. uplo ? B. data : copy (B. data' ))[1 ]
0 commit comments