Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
422
julia-0.6.2/share/julia/base/linalg/arnoldi.jl
Normal file
422
julia-0.6.2/share/julia/base/linalg/arnoldi.jl
Normal file
@@ -0,0 +1,422 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
using .ARPACK
|
||||
|
||||
## eigs
|
||||
"""
|
||||
eigs(A; nev=6, ncv=max(20,2*nev+1), which=:LM, tol=0.0, maxiter=300, sigma=nothing, ritzvec=true, v0=zeros((0,))) -> (d,[v,],nconv,niter,nmult,resid)
|
||||
|
||||
Computes eigenvalues `d` of `A` using implicitly restarted Lanczos or Arnoldi iterations for real symmetric or
|
||||
general nonsymmetric matrices respectively.
|
||||
|
||||
The following keyword arguments are supported:
|
||||
|
||||
* `nev`: Number of eigenvalues
|
||||
* `ncv`: Number of Krylov vectors used in the computation; should satisfy `nev+1 <= ncv <= n`
|
||||
for real symmetric problems and `nev+2 <= ncv <= n` for other problems, where `n` is the
|
||||
size of the input matrix `A`. The default is `ncv = max(20,2*nev+1)`. Note that these
|
||||
restrictions limit the input matrix `A` to be of dimension at least 2.
|
||||
* `which`: type of eigenvalues to compute. See the note below.
|
||||
|
||||
| `which` | type of eigenvalues |
|
||||
|:--------|:--------------------------------------------------------------------------------------------------------------------------|
|
||||
| `:LM` | eigenvalues of largest magnitude (default) |
|
||||
| `:SM` | eigenvalues of smallest magnitude |
|
||||
| `:LR` | eigenvalues of largest real part |
|
||||
| `:SR` | eigenvalues of smallest real part |
|
||||
| `:LI` | eigenvalues of largest imaginary part (nonsymmetric or complex `A` only) |
|
||||
| `:SI` | eigenvalues of smallest imaginary part (nonsymmetric or complex `A` only) |
|
||||
| `:BE` | compute half of the eigenvalues from each end of the spectrum, biased in favor of the high end. (real symmetric `A` only) |
|
||||
|
||||
* `tol`: parameter defining the relative tolerance for convergence of Ritz values (eigenvalue estimates).
|
||||
A Ritz value ``θ`` is considered converged when its associated residual
|
||||
is less than or equal to the product of `tol` and ``max(ɛ^{2/3}, |θ|)``,
|
||||
where `ɛ = eps(real(eltype(A)))/2` is LAPACK's machine epsilon.
|
||||
The residual associated with ``θ`` and its corresponding Ritz vector ``v``
|
||||
is defined as the norm ``||Av - vθ||``.
|
||||
The specified value of `tol` should be positive; otherwise, it is ignored
|
||||
and ``ɛ`` is used instead.
|
||||
Default: ``ɛ``.
|
||||
|
||||
* `maxiter`: Maximum number of iterations (default = 300)
|
||||
* `sigma`: Specifies the level shift used in inverse iteration. If `nothing` (default),
|
||||
defaults to ordinary (forward) iterations. Otherwise, find eigenvalues close to `sigma`
|
||||
using shift and invert iterations.
|
||||
* `ritzvec`: Returns the Ritz vectors `v` (eigenvectors) if `true`
|
||||
* `v0`: starting vector from which to start the iterations
|
||||
|
||||
`eigs` returns the `nev` requested eigenvalues in `d`, the corresponding Ritz vectors `v`
|
||||
(only if `ritzvec=true`), the number of converged eigenvalues `nconv`, the number of
|
||||
iterations `niter` and the number of matrix vector multiplications `nmult`, as well as the
|
||||
final residual vector `resid`.
|
||||
|
||||
# Example
|
||||
|
||||
```jldoctest
|
||||
julia> A = spdiagm(1:4);
|
||||
|
||||
julia> λ, ϕ = eigs(A, nev = 2);
|
||||
|
||||
julia> λ
|
||||
2-element Array{Float64,1}:
|
||||
4.0
|
||||
3.0
|
||||
```
|
||||
|
||||
!!! note
|
||||
The `sigma` and `which` keywords interact: the description of eigenvalues
|
||||
searched for by `which` do *not* necessarily refer to the eigenvalues of
|
||||
`A`, but rather the linear operator constructed by the specification of the
|
||||
iteration mode implied by `sigma`.
|
||||
|
||||
| `sigma` | iteration mode | `which` refers to eigenvalues of |
|
||||
|:----------------|:---------------------------------|:---------------------------------|
|
||||
| `nothing` | ordinary (forward) | ``A`` |
|
||||
| real or complex | inverse with level shift `sigma` | ``(A - \\sigma I )^{-1}`` |
|
||||
|
||||
!!! note
|
||||
Although `tol` has a default value, the best choice depends strongly on the
|
||||
matrix `A`. We recommend that users _always_ specify a value for `tol`
|
||||
which suits their specific needs.
|
||||
|
||||
For details of how the errors in the computed eigenvalues are estimated, see:
|
||||
|
||||
* B. N. Parlett, "The Symmetric Eigenvalue Problem", SIAM: Philadelphia, 2/e
|
||||
(1998), Ch. 13.2, "Accessing Accuracy in Lanczos Problems", pp. 290-292 ff.
|
||||
* R. B. Lehoucq and D. C. Sorensen, "Deflation Techniques for an Implicitly
|
||||
Restarted Arnoldi Iteration", SIAM Journal on Matrix Analysis and
|
||||
Applications (1996), 17(4), 789–821. doi:10.1137/S0895479895281484
|
||||
"""
|
||||
eigs(A; kwargs...) = eigs(A, I; kwargs...)
|
||||
eigs(A::AbstractMatrix{<:BlasFloat}, ::UniformScaling; kwargs...) = _eigs(A, I; kwargs...)
|
||||
|
||||
eigs(A::AbstractMatrix{T}, B::AbstractMatrix{T}; kwargs...) where {T<:BlasFloat} = _eigs(A, B; kwargs...)
|
||||
eigs(A::AbstractMatrix{BigFloat}, B::AbstractMatrix...; kwargs...) = throw(MethodError(eigs, Any[A,B,kwargs...]))
|
||||
eigs(A::AbstractMatrix{BigFloat}, B::UniformScaling; kwargs...) = throw(MethodError(eigs, Any[A,B,kwargs...]))
|
||||
function eigs(A::AbstractMatrix{T}, ::UniformScaling; kwargs...) where T
|
||||
Tnew = typeof(zero(T)/sqrt(one(T)))
|
||||
eigs(convert(AbstractMatrix{Tnew}, A), I; kwargs...)
|
||||
end
|
||||
function eigs(A::AbstractMatrix, B::AbstractMatrix; kwargs...)
|
||||
T = promote_type(eltype(A), eltype(B))
|
||||
Tnew = typeof(zero(T)/sqrt(one(T)))
|
||||
eigs(convert(AbstractMatrix{Tnew}, A), convert(AbstractMatrix{Tnew}, B); kwargs...)
|
||||
end
|
||||
"""
|
||||
eigs(A, B; nev=6, ncv=max(20,2*nev+1), which=:LM, tol=0.0, maxiter=300, sigma=nothing, ritzvec=true, v0=zeros((0,))) -> (d,[v,],nconv,niter,nmult,resid)
|
||||
|
||||
Computes generalized eigenvalues `d` of `A` and `B` using implicitly restarted Lanczos or Arnoldi iterations for
|
||||
real symmetric or general nonsymmetric matrices respectively.
|
||||
|
||||
The following keyword arguments are supported:
|
||||
|
||||
* `nev`: Number of eigenvalues
|
||||
* `ncv`: Number of Krylov vectors used in the computation; should satisfy `nev+1 <= ncv <= n`
|
||||
for real symmetric problems and `nev+2 <= ncv <= n` for other problems, where `n` is the
|
||||
size of the input matrices `A` and `B`. The default is `ncv = max(20,2*nev+1)`. Note that
|
||||
these restrictions limit the input matrix `A` to be of dimension at least 2.
|
||||
* `which`: type of eigenvalues to compute. See the note below.
|
||||
|
||||
| `which` | type of eigenvalues |
|
||||
|:--------|:--------------------------------------------------------------------------------------------------------------------------|
|
||||
| `:LM` | eigenvalues of largest magnitude (default) |
|
||||
| `:SM` | eigenvalues of smallest magnitude |
|
||||
| `:LR` | eigenvalues of largest real part |
|
||||
| `:SR` | eigenvalues of smallest real part |
|
||||
| `:LI` | eigenvalues of largest imaginary part (nonsymmetric or complex `A` only) |
|
||||
| `:SI` | eigenvalues of smallest imaginary part (nonsymmetric or complex `A` only) |
|
||||
| `:BE` | compute half of the eigenvalues from each end of the spectrum, biased in favor of the high end. (real symmetric `A` only) |
|
||||
|
||||
* `tol`: relative tolerance used in the convergence criterion for eigenvalues, similar to
|
||||
`tol` in the [`eigs(A)`](@ref) method for the ordinary eigenvalue
|
||||
problem, but effectively for the eigenvalues of ``B^{-1} A`` instead of ``A``.
|
||||
See the documentation for the ordinary eigenvalue problem in
|
||||
[`eigs(A)`](@ref) and the accompanying note about `tol`.
|
||||
* `maxiter`: Maximum number of iterations (default = 300)
|
||||
* `sigma`: Specifies the level shift used in inverse iteration. If `nothing` (default),
|
||||
defaults to ordinary (forward) iterations. Otherwise, find eigenvalues close to `sigma`
|
||||
using shift and invert iterations.
|
||||
* `ritzvec`: Returns the Ritz vectors `v` (eigenvectors) if `true`
|
||||
* `v0`: starting vector from which to start the iterations
|
||||
|
||||
`eigs` returns the `nev` requested eigenvalues in `d`, the corresponding Ritz vectors `v`
|
||||
(only if `ritzvec=true`), the number of converged eigenvalues `nconv`, the number of
|
||||
iterations `niter` and the number of matrix vector multiplications `nmult`, as well as the
|
||||
final residual vector `resid`.
|
||||
|
||||
# Example
|
||||
|
||||
```jldoctest
|
||||
julia> A = speye(4, 4); B = spdiagm(1:4);
|
||||
|
||||
julia> λ, ϕ = eigs(A, B, nev = 2);
|
||||
|
||||
julia> λ
|
||||
2-element Array{Float64,1}:
|
||||
1.0
|
||||
0.5
|
||||
```
|
||||
|
||||
!!! note
|
||||
The `sigma` and `which` keywords interact: the description of eigenvalues searched for by
|
||||
`which` do *not* necessarily refer to the eigenvalue problem ``Av = Bv\\lambda``, but rather
|
||||
the linear operator constructed by the specification of the iteration mode implied by `sigma`.
|
||||
|
||||
| `sigma` | iteration mode | `which` refers to the problem |
|
||||
|:----------------|:---------------------------------|:-----------------------------------|
|
||||
| `nothing` | ordinary (forward) | ``Av = Bv\\lambda`` |
|
||||
| real or complex | inverse with level shift `sigma` | ``(A - \\sigma B )^{-1}B = v\\nu`` |
|
||||
"""
|
||||
eigs(A, B; kwargs...) = _eigs(A, B; kwargs...)
|
||||
function _eigs(A, B;
|
||||
nev::Integer=6, ncv::Integer=max(20,2*nev+1), which=:LM,
|
||||
tol=0.0, maxiter::Integer=300, sigma=nothing, v0::Vector=zeros(eltype(A),(0,)),
|
||||
ritzvec::Bool=true)
|
||||
n = checksquare(A)
|
||||
|
||||
T = eltype(A)
|
||||
iscmplx = T <: Complex
|
||||
isgeneral = B !== I
|
||||
sym = issymmetric(A) && issymmetric(B) && !iscmplx
|
||||
nevmax=sym ? n-1 : n-2
|
||||
if nevmax <= 0
|
||||
throw(ArgumentError("input matrix A is too small. Use eigfact instead."))
|
||||
end
|
||||
if nev > nevmax
|
||||
warn("Adjusting nev from $nev to $nevmax")
|
||||
nev = nevmax
|
||||
end
|
||||
if nev <= 0
|
||||
throw(ArgumentError("requested number of eigenvalues (nev) must be ≥ 1, got $nev"))
|
||||
end
|
||||
ncvmin = nev + (sym ? 1 : 2)
|
||||
if ncv < ncvmin
|
||||
warn("Adjusting ncv from $ncv to $ncvmin")
|
||||
ncv = ncvmin
|
||||
end
|
||||
ncv = BlasInt(min(ncv, n))
|
||||
bmat = isgeneral ? "G" : "I"
|
||||
isshift = sigma !== nothing
|
||||
|
||||
if isa(which,AbstractString)
|
||||
warn("Use symbols instead of strings for specifying which eigenvalues to compute")
|
||||
which=Symbol(which)
|
||||
end
|
||||
if (which != :LM && which != :SM && which != :LR && which != :SR &&
|
||||
which != :LI && which != :SI && which != :BE)
|
||||
throw(ArgumentError("which must be :LM, :SM, :LR, :SR, :LI, :SI, or :BE, got $(repr(which))"))
|
||||
end
|
||||
if which == :BE && !sym
|
||||
throw(ArgumentError("which=:BE only possible for real symmetric problem"))
|
||||
end
|
||||
isshift && which == :SM && warn("use of :SM in shift-and-invert mode is not recommended, use :LM to find eigenvalues closest to sigma")
|
||||
|
||||
if which==:SM && !isshift # transform into shift-and-invert method with sigma = 0
|
||||
isshift=true
|
||||
sigma=zero(T)
|
||||
which=:LM
|
||||
end
|
||||
|
||||
if sigma !== nothing && !iscmplx && isa(sigma,Complex)
|
||||
throw(ArgumentError("complex shifts for real problems are not yet supported"))
|
||||
end
|
||||
sigma = isshift ? convert(T,sigma) : zero(T)
|
||||
|
||||
if !isempty(v0)
|
||||
if length(v0) != n
|
||||
throw(DimensionMismatch())
|
||||
end
|
||||
if eltype(v0) != T
|
||||
throw(ArgumentError("starting vector must have element type $T, got $(eltype(v0))"))
|
||||
end
|
||||
end
|
||||
|
||||
whichstr = "LM"
|
||||
if which == :BE
|
||||
whichstr = "BE"
|
||||
end
|
||||
if which == :LR
|
||||
whichstr = (!sym ? "LR" : "LA")
|
||||
end
|
||||
if which == :SR
|
||||
whichstr = (!sym ? "SR" : "SA")
|
||||
end
|
||||
if which == :LI
|
||||
if !sym
|
||||
whichstr = "LI"
|
||||
else
|
||||
throw(ArgumentError("largest imaginary is meaningless for symmetric eigenvalue problems"))
|
||||
end
|
||||
end
|
||||
if which == :SI
|
||||
if !sym
|
||||
whichstr = "SI"
|
||||
else
|
||||
throw(ArgumentError("smallest imaginary is meaningless for symmetric eigenvalue problems"))
|
||||
end
|
||||
end
|
||||
|
||||
# Refer to ex-*.doc files in ARPACK/DOCUMENTS for calling sequence
|
||||
matvecA!(y, x) = A_mul_B!(y, A, x)
|
||||
if !isgeneral # Standard problem
|
||||
matvecB = x -> x
|
||||
if !isshift # Regular mode
|
||||
mode = 1
|
||||
solveSI = x->x
|
||||
else # Shift-invert mode
|
||||
mode = 3
|
||||
F = factorize(A - UniformScaling(sigma))
|
||||
solveSI = x -> F \ x
|
||||
end
|
||||
else # Generalized eigenproblem
|
||||
matvecB = x -> B * x
|
||||
if !isshift # Regular inverse mode
|
||||
mode = 2
|
||||
F = factorize(B)
|
||||
solveSI = x -> F \ x
|
||||
else # Shift-invert mode
|
||||
mode = 3
|
||||
F = factorize(A - sigma*B)
|
||||
solveSI = x -> F \ x
|
||||
end
|
||||
end
|
||||
|
||||
# Compute the Ritz values and Ritz vectors
|
||||
(resid, v, ldv, iparam, ipntr, workd, workl, lworkl, rwork, TOL) =
|
||||
ARPACK.aupd_wrapper(T, matvecA!, matvecB, solveSI, n, sym, iscmplx, bmat, nev, ncv, whichstr, tol, maxiter, mode, v0)
|
||||
|
||||
# Postprocessing to get eigenvalues and eigenvectors
|
||||
output = ARPACK.eupd_wrapper(T, n, sym, iscmplx, bmat, nev, whichstr, ritzvec, TOL,
|
||||
resid, ncv, v, ldv, sigma, iparam, ipntr, workd, workl, lworkl, rwork)
|
||||
|
||||
# Issue 10495, 10701: Check that all eigenvalues are converged
|
||||
nev = length(output[1])
|
||||
nconv = output[ritzvec ? 3 : 2]
|
||||
nev ≤ nconv || warn("not all wanted Ritz pairs converged. Requested: $nev, converged: $nconv")
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
|
||||
## svds
|
||||
### Restrict operator to BlasFloat because ARPACK only supports that. Loosen restriction
|
||||
### when we switch to our own implementation
|
||||
mutable struct SVDOperator{T<:BlasFloat,S} <: AbstractArray{T, 2}
|
||||
X::S
|
||||
m::Int
|
||||
n::Int
|
||||
SVDOperator{T,S}(X::AbstractMatrix) where {T<:BlasFloat,S} = new(X, size(X, 1), size(X, 2))
|
||||
end
|
||||
|
||||
function SVDOperator(A::AbstractMatrix{T}) where T
|
||||
Tnew = typeof(zero(T)/sqrt(one(T)))
|
||||
Anew = convert(AbstractMatrix{Tnew}, A)
|
||||
SVDOperator{Tnew,typeof(Anew)}(Anew)
|
||||
end
|
||||
|
||||
function A_mul_B!(u::StridedVector{T}, s::SVDOperator{T}, v::StridedVector{T}) where T
|
||||
a, b = s.m, length(v)
|
||||
A_mul_B!(view(u,1:a), s.X, view(v,a+1:b)) # left singular vector
|
||||
Ac_mul_B!(view(u,a+1:b), s.X, view(v,1:a)) # right singular vector
|
||||
u
|
||||
end
|
||||
size(s::SVDOperator) = s.m + s.n, s.m + s.n
|
||||
issymmetric(s::SVDOperator) = true
|
||||
|
||||
svds(A::AbstractMatrix{<:BlasFloat}; kwargs...) = _svds(A; kwargs...)
|
||||
svds(A::AbstractMatrix{BigFloat}; kwargs...) = throw(MethodError(svds, Any[A, kwargs...]))
|
||||
function svds(A::AbstractMatrix{T}; kwargs...) where T
|
||||
Tnew = typeof(zero(T)/sqrt(one(T)))
|
||||
svds(convert(AbstractMatrix{Tnew}, A); kwargs...)
|
||||
end
|
||||
|
||||
"""
|
||||
svds(A; nsv=6, ritzvec=true, tol=0.0, maxiter=1000, ncv=2*nsv, u0=zeros((0,)), v0=zeros((0,))) -> (SVD([left_sv,] s, [right_sv,]), nconv, niter, nmult, resid)
|
||||
|
||||
Computes the largest singular values `s` of `A` using implicitly restarted Lanczos
|
||||
iterations derived from [`eigs`](@ref).
|
||||
|
||||
**Inputs**
|
||||
|
||||
* `A`: Linear operator whose singular values are desired. `A` may be represented as a
|
||||
subtype of `AbstractArray`, e.g., a sparse matrix, or any other type supporting the four
|
||||
methods `size(A)`, `eltype(A)`, `A * vector`, and `A' * vector`.
|
||||
* `nsv`: Number of singular values. Default: 6.
|
||||
* `ritzvec`: If `true`, return the left and right singular vectors `left_sv` and `right_sv`.
|
||||
If `false`, omit the singular vectors. Default: `true`.
|
||||
* `tol`: tolerance, see [`eigs`](@ref).
|
||||
* `maxiter`: Maximum number of iterations, see [`eigs`](@ref). Default: 1000.
|
||||
* `ncv`: Maximum size of the Krylov subspace, see [`eigs`](@ref) (there called `nev`). Default: `2*nsv`.
|
||||
* `u0`: Initial guess for the first left Krylov vector. It may have length `m` (the first dimension of `A`), or 0.
|
||||
* `v0`: Initial guess for the first right Krylov vector. It may have length `n` (the second dimension of `A`), or 0.
|
||||
|
||||
**Outputs**
|
||||
|
||||
* `svd`: An `SVD` object containing the left singular vectors, the requested values, and the
|
||||
right singular vectors. If `ritzvec = false`, the left and right singular vectors will be
|
||||
empty.
|
||||
* `nconv`: Number of converged singular values.
|
||||
* `niter`: Number of iterations.
|
||||
* `nmult`: Number of matrix--vector products used.
|
||||
* `resid`: Final residual vector.
|
||||
|
||||
# Example
|
||||
|
||||
```jldoctest
|
||||
julia> A = spdiagm(1:4);
|
||||
|
||||
julia> s = svds(A, nsv = 2)[1];
|
||||
|
||||
julia> s[:S]
|
||||
2-element Array{Float64,1}:
|
||||
4.0
|
||||
3.0
|
||||
```
|
||||
|
||||
!!! note "Implementation"
|
||||
`svds(A)` is formally equivalent to calling [`eigs`](@ref) to perform implicitly restarted
|
||||
Lanczos tridiagonalization on the Hermitian matrix
|
||||
``\\begin{pmatrix} 0 & A^\\prime \\\\ A & 0 \\end{pmatrix}``, whose eigenvalues are
|
||||
plus and minus the singular values of ``A``.
|
||||
"""
|
||||
svds(A; kwargs...) = _svds(A; kwargs...)
|
||||
function _svds(X; nsv::Int = 6, ritzvec::Bool = true, tol::Float64 = 0.0, maxiter::Int = 1000, ncv::Int = 2*nsv, u0::Vector=zeros(eltype(X),(0,)), v0::Vector=zeros(eltype(X),(0,)))
|
||||
if nsv < 1
|
||||
throw(ArgumentError("number of singular values (nsv) must be ≥ 1, got $nsv"))
|
||||
end
|
||||
if nsv > minimum(size(X))
|
||||
throw(ArgumentError("number of singular values (nsv) must be ≤ $(minimum(size(X))), got $nsv"))
|
||||
end
|
||||
m,n = size(X)
|
||||
otype = eltype(X)
|
||||
padv0 = zeros(eltype(X),(0,))
|
||||
if length(v0) ∉ [0,n]
|
||||
throw(DimensionMismatch("length of v0, the guess for the starting right Krylov vector, must be 0, or $n, got $(length(v0))"))
|
||||
end
|
||||
if length(u0) ∉ [0,m]
|
||||
throw(DimensionMismatch("length of u0, the guess for the starting left Krylov vector, must be 0, or $m, got $(length(u0))"))
|
||||
end
|
||||
if length(v0) == n && length(u0) == m
|
||||
padv0 = [u0; v0]
|
||||
elseif length(v0) == n && length(u0) == 0
|
||||
padv0 = [zeros(otype,m); v0]
|
||||
elseif length(v0) == 0 && length(u0) == m
|
||||
padv0 = [u0; zeros(otype,n) ]
|
||||
end
|
||||
ex = eigs(SVDOperator(X), I; ritzvec = ritzvec, nev = ncv, tol = tol, maxiter = maxiter, v0=padv0)
|
||||
ind = [1:2:ncv;]
|
||||
sval = abs.(ex[1][ind])
|
||||
|
||||
if ritzvec
|
||||
# calculating singular vectors
|
||||
left_sv = sqrt(2) * ex[2][ 1:size(X,1), ind ] .* sign.(ex[1][ind]')
|
||||
right_sv = sqrt(2) * ex[2][ size(X,1)+1:end, ind ]
|
||||
return (SVD(left_sv, sval, right_sv'), ex[3], ex[4], ex[5], ex[6])
|
||||
else
|
||||
#The sort is necessary to work around #10329
|
||||
return (SVD(zeros(eltype(sval), n, 0),
|
||||
sort!(sval, by=real, rev=true),
|
||||
zeros(eltype(sval), 0, m)),
|
||||
ex[2], ex[3], ex[4], ex[5])
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user