Line | Exclusive | Inclusive | Code |
---|---|---|---|
1 | # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
2 | |||
3 | # preserve HermOrSym wrapper | ||
4 | eigencopy_oftype(A::Hermitian, S) = Hermitian(copy_similar(A, S), sym_uplo(A.uplo)) | ||
5 | 88 (31 %) |
88 (100 %)
samples spent calling
copy_similar
eigencopy_oftype(A::Symmetric, S) = Symmetric(copy_similar(A, S), sym_uplo(A.uplo))
|
|
6 | |||
7 | # Eigensolvers for symmetric and Hermitian matrices | ||
8 | eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}; sortby::Union{Function,Nothing}=nothing) = | ||
9 | Eigen(sorteig!(LAPACK.syevr!('V', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)..., sortby)...) | ||
10 | |||
11 | function eigen(A::RealHermSymComplexHerm; sortby::Union{Function,Nothing}=nothing) | ||
12 | S = eigtype(eltype(A)) | ||
13 | eigen!(eigencopy_oftype(A, S), sortby=sortby) | ||
14 | end | ||
15 | |||
16 | eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, irange::UnitRange) = | ||
17 | Eigen(LAPACK.syevr!('V', 'I', A.uplo, A.data, 0.0, 0.0, irange.start, irange.stop, -1.0)...) | ||
18 | |||
19 | """ | ||
20 | eigen(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> Eigen | ||
21 | |||
22 | Compute the eigenvalue decomposition of `A`, returning an [`Eigen`](@ref) factorization object `F` | ||
23 | which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the | ||
24 | matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) | ||
25 | |||
26 | Iterating the decomposition produces the components `F.values` and `F.vectors`. | ||
27 | |||
28 | The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). | ||
29 | |||
30 | The [`UnitRange`](@ref) `irange` specifies indices of the sorted eigenvalues to search for. | ||
31 | |||
32 | !!! note | ||
33 | If `irange` is not `1:n`, where `n` is the dimension of `A`, then the returned factorization | ||
34 | will be a *truncated* factorization. | ||
35 | """ | ||
36 | function eigen(A::RealHermSymComplexHerm, irange::UnitRange) | ||
37 | S = eigtype(eltype(A)) | ||
38 | eigen!(eigencopy_oftype(A, S), irange) | ||
39 | end | ||
40 | |||
41 | eigen!(A::RealHermSymComplexHerm{T,<:StridedMatrix}, vl::Real, vh::Real) where {T<:BlasReal} = | ||
42 | Eigen(LAPACK.syevr!('V', 'V', A.uplo, A.data, convert(T, vl), convert(T, vh), 0, 0, -1.0)...) | ||
43 | |||
44 | """ | ||
45 | eigen(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> Eigen | ||
46 | |||
47 | Compute the eigenvalue decomposition of `A`, returning an [`Eigen`](@ref) factorization object `F` | ||
48 | which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the | ||
49 | matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) | ||
50 | |||
51 | Iterating the decomposition produces the components `F.values` and `F.vectors`. | ||
52 | |||
53 | The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). | ||
54 | |||
55 | `vl` is the lower bound of the window of eigenvalues to search for, and `vu` is the upper bound. | ||
56 | |||
57 | !!! note | ||
58 | If [`vl`, `vu`] does not contain all eigenvalues of `A`, then the returned factorization | ||
59 | will be a *truncated* factorization. | ||
60 | """ | ||
61 | function eigen(A::RealHermSymComplexHerm, vl::Real, vh::Real) | ||
62 | S = eigtype(eltype(A)) | ||
63 | eigen!(eigencopy_oftype(A, S), vl, vh) | ||
64 | end | ||
65 | |||
66 | function eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}; sortby::Union{Function,Nothing}=nothing) | ||
67 | vals = LAPACK.syevr!('N', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)[1] | ||
68 | !isnothing(sortby) && sort!(vals, by=sortby) | ||
69 | return vals | ||
70 | end | ||
71 | |||
72 | function eigvals(A::RealHermSymComplexHerm; sortby::Union{Function,Nothing}=nothing) | ||
73 | S = eigtype(eltype(A)) | ||
74 | eigvals!(eigencopy_oftype(A, S), sortby=sortby) | ||
75 | end | ||
76 | |||
77 | """ | ||
78 | eigvals!(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> values | ||
79 | |||
80 | Same as [`eigvals`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. | ||
81 | `irange` is a range of eigenvalue *indices* to search for - for instance, the 2nd to 8th eigenvalues. | ||
82 | """ | ||
83 | eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, irange::UnitRange) = | ||
84 | LAPACK.syevr!('N', 'I', A.uplo, A.data, 0.0, 0.0, irange.start, irange.stop, -1.0)[1] | ||
85 | |||
86 | """ | ||
87 | eigvals(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> values | ||
88 | |||
89 | Return the eigenvalues of `A`. It is possible to calculate only a subset of the | ||
90 | eigenvalues by specifying a [`UnitRange`](@ref) `irange` covering indices of the sorted eigenvalues, | ||
91 | e.g. the 2nd to 8th eigenvalues. | ||
92 | |||
93 | # Examples | ||
94 | ```jldoctest | ||
95 | julia> A = SymTridiagonal([1.; 2.; 1.], [2.; 3.]) | ||
96 | 3×3 SymTridiagonal{Float64, Vector{Float64}}: | ||
97 | 1.0 2.0 ⋅ | ||
98 | 2.0 2.0 3.0 | ||
99 | ⋅ 3.0 1.0 | ||
100 | |||
101 | julia> eigvals(A, 2:2) | ||
102 | 1-element Vector{Float64}: | ||
103 | 0.9999999999999996 | ||
104 | |||
105 | julia> eigvals(A) | ||
106 | 3-element Vector{Float64}: | ||
107 | -2.1400549446402604 | ||
108 | 1.0000000000000002 | ||
109 | 5.140054944640259 | ||
110 | ``` | ||
111 | """ | ||
112 | function eigvals(A::RealHermSymComplexHerm, irange::UnitRange) | ||
113 | S = eigtype(eltype(A)) | ||
114 | eigvals!(eigencopy_oftype(A, S), irange) | ||
115 | end | ||
116 | |||
117 | """ | ||
118 | eigvals!(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> values | ||
119 | |||
120 | Same as [`eigvals`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. | ||
121 | `vl` is the lower bound of the interval to search for eigenvalues, and `vu` is the upper bound. | ||
122 | """ | ||
123 | eigvals!(A::RealHermSymComplexHerm{T,<:StridedMatrix}, vl::Real, vh::Real) where {T<:BlasReal} = | ||
124 | LAPACK.syevr!('N', 'V', A.uplo, A.data, convert(T, vl), convert(T, vh), 0, 0, -1.0)[1] | ||
125 | |||
126 | """ | ||
127 | eigvals(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> values | ||
128 | |||
129 | Return the eigenvalues of `A`. It is possible to calculate only a subset of the eigenvalues | ||
130 | by specifying a pair `vl` and `vu` for the lower and upper boundaries of the eigenvalues. | ||
131 | |||
132 | # Examples | ||
133 | ```jldoctest | ||
134 | julia> A = SymTridiagonal([1.; 2.; 1.], [2.; 3.]) | ||
135 | 3×3 SymTridiagonal{Float64, Vector{Float64}}: | ||
136 | 1.0 2.0 ⋅ | ||
137 | 2.0 2.0 3.0 | ||
138 | ⋅ 3.0 1.0 | ||
139 | |||
140 | julia> eigvals(A, -1, 2) | ||
141 | 1-element Vector{Float64}: | ||
142 | 1.0000000000000009 | ||
143 | |||
144 | julia> eigvals(A) | ||
145 | 3-element Vector{Float64}: | ||
146 | -2.1400549446402604 | ||
147 | 1.0000000000000002 | ||
148 | 5.140054944640259 | ||
149 | ``` | ||
150 | """ | ||
151 | function eigvals(A::RealHermSymComplexHerm, vl::Real, vh::Real) | ||
152 | S = eigtype(eltype(A)) | ||
153 | eigvals!(eigencopy_oftype(A, S), vl, vh) | ||
154 | end | ||
155 | |||
156 | eigmax(A::RealHermSymComplexHerm{<:Real}) = eigvals(A, size(A, 1):size(A, 1))[1] | ||
157 | eigmin(A::RealHermSymComplexHerm{<:Real}) = eigvals(A, 1:1)[1] | ||
158 | |||
159 | function eigen(A::HermOrSym{TA}, B::HermOrSym{TB}; kws...) where {TA,TB} | ||
160 | S = promote_type(eigtype(TA), TB) | ||
161 | return eigen!(eigencopy_oftype(A, S), eigencopy_oftype(B, S); kws...) | ||
162 | end | ||
163 | |||
164 | function eigen!(A::HermOrSym{T,S}, B::HermOrSym{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasReal,S<:StridedMatrix} | ||
165 | vals, vecs, _ = LAPACK.sygvd!(1, 'V', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data')) | ||
166 | GeneralizedEigen(sorteig!(vals, vecs, sortby)...) | ||
167 | end | ||
168 | function eigen!(A::Hermitian{T,S}, B::Hermitian{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasComplex,S<:StridedMatrix} | ||
169 | vals, vecs, _ = LAPACK.sygvd!(1, 'V', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data')) | ||
170 | GeneralizedEigen(sorteig!(vals, vecs, sortby)...) | ||
171 | end | ||
172 | |||
173 | function eigen(A::AbstractMatrix, C::Cholesky; sortby::Union{Function,Nothing}=nothing) | ||
174 | if ishermitian(A) | ||
175 | eigen!(eigencopy_oftype(Hermitian(A), eigtype(eltype(A))), C; sortby) | ||
176 | else | ||
177 | eigen!(copy_similar(A, eigtype(eltype(A))), C; sortby) | ||
178 | end | ||
179 | end | ||
180 | function eigen!(A::AbstractMatrix, C::Cholesky; sortby::Union{Function,Nothing}=nothing) | ||
181 | # Cholesky decomposition based eigenvalues and eigenvectors | ||
182 | vals, w = eigen!(UtiAUi!(A, C.U)) | ||
183 | vecs = C.U \ w | ||
184 | GeneralizedEigen(sorteig!(vals, vecs, sortby)...) | ||
185 | end | ||
186 | |||
187 | # Perform U' \ A / U in-place, where U::Union{UpperTriangular,Diagonal} | ||
188 | UtiAUi!(A, U) = _UtiAUi!(A, U) | ||
189 | UtiAUi!(A::Symmetric, U) = Symmetric(_UtiAUi!(copytri!(parent(A), A.uplo), U), sym_uplo(A.uplo)) | ||
190 | UtiAUi!(A::Hermitian, U) = Hermitian(_UtiAUi!(copytri!(parent(A), A.uplo, true), U), sym_uplo(A.uplo)) | ||
191 | _UtiAUi!(A, U) = rdiv!(ldiv!(U', A), U) | ||
192 | |||
193 | function eigvals(A::HermOrSym{TA}, B::HermOrSym{TB}; kws...) where {TA,TB} | ||
194 | S = promote_type(eigtype(TA), TB) | ||
195 | return eigvals!(eigencopy_oftype(A, S), eigencopy_oftype(B, S); kws...) | ||
196 | end | ||
197 | |||
198 | function eigvals!(A::HermOrSym{T,S}, B::HermOrSym{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasReal,S<:StridedMatrix} | ||
199 | vals = LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data'))[1] | ||
200 | isnothing(sortby) || sort!(vals, by=sortby) | ||
201 | return vals | ||
202 | end | ||
203 | function eigvals!(A::Hermitian{T,S}, B::Hermitian{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasComplex,S<:StridedMatrix} | ||
204 | vals = LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data'))[1] | ||
205 | isnothing(sortby) || sort!(vals, by=sortby) | ||
206 | return vals | ||
207 | end | ||
208 | eigvecs(A::HermOrSym) = eigvecs(eigen(A)) | ||
209 | |||
210 | function eigvals(A::AbstractMatrix, C::Cholesky; sortby::Union{Function,Nothing}=nothing) | ||
211 | if ishermitian(A) | ||
212 | eigvals!(eigencopy_oftype(Hermitian(A), eigtype(eltype(A))), C; sortby) | ||
213 | else | ||
214 | eigvals!(copy_similar(A, eigtype(eltype(A))), C; sortby) | ||
215 | end | ||
216 | end | ||
217 | function eigvals!(A::AbstractMatrix{T}, C::Cholesky{T, <:AbstractMatrix}; sortby::Union{Function,Nothing}=nothing) where {T<:Number} | ||
218 | # Cholesky decomposition based eigenvalues | ||
219 | return eigvals!(UtiAUi!(A, C.U); sortby) | ||
220 | end |