Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Move iterative eigensolvers to the stdlib #24714

Merged
merged 1 commit into from
Nov 26, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Move iterative eigensolvers to the stdlib
  • Loading branch information
ararslan committed Nov 26, 2017
commit b9b568de1b74666b7d24a2e41e9e65e5cd1d81ed
3 changes: 3 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,9 @@ export conv, conv2, deconv, filt, filt!, xcorr
@eval @deprecate_moved $(Symbol("@dateformat_str")) "Dates" true true
@deprecate_moved now "Dates" true true

@deprecate_moved eigs "IterativeEigenSolvers" true true
@deprecate_moved svds "IterativeEigenSolvers" true true

# PR #21709
@deprecate cov(x::AbstractVector, corrected::Bool) cov(x, corrected=corrected)
@deprecate cov(x::AbstractMatrix, vardim::Int, corrected::Bool) cov(x, vardim, corrected=corrected)
Expand Down
2 changes: 0 additions & 2 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,6 @@ export
eigfact,
eigmax,
eigmin,
eigs,
eigvals,
eigvals!,
eigvecs,
Expand Down Expand Up @@ -602,7 +601,6 @@ export
svd,
svdfact!,
svdfact,
svds,
svdvals!,
svdvals,
sylvester,
Expand Down
5 changes: 0 additions & 5 deletions base/linalg/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export
eigfact!,
eigmax,
eigmin,
eigs,
eigvals,
eigvals!,
eigvecs,
Expand Down Expand Up @@ -131,7 +130,6 @@ export
svd,
svdfact!,
svdfact,
svds,
svdvals!,
svdvals,
sylvester,
Expand Down Expand Up @@ -277,9 +275,6 @@ include("ldlt.jl")
include("schur.jl")


include("arpack.jl")
include("arnoldi.jl")

function __init__()
try
BLAS.check()
Expand Down
2 changes: 1 addition & 1 deletion base/sparse/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ end

chol(A::SparseMatrixCSC) = error("Use cholfact() instead of chol() for sparse matrices.")
lu(A::SparseMatrixCSC) = error("Use lufact() instead of lu() for sparse matrices.")
eig(A::SparseMatrixCSC) = error("Use eigs() instead of eig() for sparse matrices.")
eig(A::SparseMatrixCSC) = error("Use IterativeEigenSolvers.eigs() instead of eig() for sparse matrices.")

function Base.cov(X::SparseMatrixCSC, vardim::Int=1; corrected::Bool=true)
a, b = size(X)
Expand Down
2 changes: 1 addition & 1 deletion base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -490,13 +490,13 @@ Base.require(:CRC32c)
Base.require(:Dates)
Base.require(:DelimitedFiles)
Base.require(:FileWatching)
Base.require(:IterativeEigenSolvers)
Base.require(:Mmap)
Base.require(:Profile)
Base.require(:SharedArrays)
Base.require(:SuiteSparse)
Base.require(:Test)


empty!(LOAD_PATH)

Base.isfile("userimg.jl") && Base.include(Main, "userimg.jl")
45 changes: 25 additions & 20 deletions doc/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,27 @@ cp_q(src, dest) = isfile(dest) || cp(src, dest)

# make links for stdlib package docs
if Sys.iswindows()
cp_q("../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md")
cp_q("../stdlib/Test/docs/src/index.md", "src/stdlib/test.md")
cp_q("../stdlib/Mmap/docs/src/index.md", "src/stdlib/mmap.md")
cp_q("../stdlib/SharedArrays/docs/src/index.md", "src/stdlib/sharedarrays.md")
cp_q("../stdlib/Profile/docs/src/index.md", "src/stdlib/profile.md")
cp_q("../stdlib/Base64/docs/src/index.md", "src/stdlib/base64.md")
cp_q("../stdlib/FileWatching/docs/src/index.md", "src/stdlib/filewatching.md")
cp_q("../stdlib/CRC32c/docs/src/index.md", "src/stdlib/crc32c.md")
cp_q("../stdlib/Dates/docs/src/index.md", "src/stdlib/dates.md")
cp_q("../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md")
cp_q("../stdlib/Test/docs/src/index.md", "src/stdlib/test.md")
cp_q("../stdlib/Mmap/docs/src/index.md", "src/stdlib/mmap.md")
cp_q("../stdlib/SharedArrays/docs/src/index.md", "src/stdlib/sharedarrays.md")
cp_q("../stdlib/Profile/docs/src/index.md", "src/stdlib/profile.md")
cp_q("../stdlib/Base64/docs/src/index.md", "src/stdlib/base64.md")
cp_q("../stdlib/FileWatching/docs/src/index.md", "src/stdlib/filewatching.md")
cp_q("../stdlib/CRC32c/docs/src/index.md", "src/stdlib/crc32c.md")
cp_q("../stdlib/Dates/docs/src/index.md", "src/stdlib/dates.md")
cp_q("../stdlib/IterativeEigenSolvers/docs/src/index.md", "src/stdlib/iterativeeigensolvers.md")
else
symlink_q("../../../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md")
symlink_q("../../../stdlib/Test/docs/src/index.md", "src/stdlib/test.md")
symlink_q("../../../stdlib/Mmap/docs/src/index.md", "src/stdlib/mmap.md")
symlink_q("../../../stdlib/SharedArrays/docs/src/index.md", "src/stdlib/sharedarrays.md")
symlink_q("../../../stdlib/Profile/docs/src/index.md", "src/stdlib/profile.md")
symlink_q("../../../stdlib/Base64/docs/src/index.md", "src/stdlib/base64.md")
symlink_q("../../../stdlib/FileWatching/docs/src/index.md", "src/stdlib/filewatching.md")
symlink_q("../../../stdlib/CRC32c/docs/src/index.md", "src/stdlib/crc32c.md")
symlink_q("../../../stdlib/Dates/docs/src/index.md", "src/stdlib/dates.md")
symlink_q("../../../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md")
symlink_q("../../../stdlib/Test/docs/src/index.md", "src/stdlib/test.md")
symlink_q("../../../stdlib/Mmap/docs/src/index.md", "src/stdlib/mmap.md")
symlink_q("../../../stdlib/SharedArrays/docs/src/index.md", "src/stdlib/sharedarrays.md")
symlink_q("../../../stdlib/Profile/docs/src/index.md", "src/stdlib/profile.md")
symlink_q("../../../stdlib/Base64/docs/src/index.md", "src/stdlib/base64.md")
symlink_q("../../../stdlib/FileWatching/docs/src/index.md", "src/stdlib/filewatching.md")
symlink_q("../../../stdlib/CRC32c/docs/src/index.md", "src/stdlib/crc32c.md")
symlink_q("../../../stdlib/Dates/docs/src/index.md", "src/stdlib/dates.md")
symlink_q("../../../stdlib/IterativeEigenSolvers/docs/src/index.md", "src/stdlib/iterativeeigensolvers.md")
end

const PAGES = [
Expand Down Expand Up @@ -114,6 +116,7 @@ const PAGES = [
"stdlib/sharedarrays.md",
"stdlib/filewatching.md",
"stdlib/crc32c.md",
"stdlib/iterativeeigensolvers.md",
],
"Developer Documentation" => [
"devdocs/reflection.md",
Expand Down Expand Up @@ -148,11 +151,13 @@ const PAGES = [
],
]

using DelimitedFiles, Test, Mmap, SharedArrays, Profile, Base64, FileWatching, CRC32c, Dates
using DelimitedFiles, Test, Mmap, SharedArrays, Profile, Base64, FileWatching, CRC32c,
Dates, IterativeEigenSolvers

makedocs(
build = joinpath(pwd(), "_build/html/en"),
modules = [Base, Core, BuildSysImg, DelimitedFiles, Test, Mmap, SharedArrays, Profile, Base64, FileWatching, Dates],
modules = [Base, Core, BuildSysImg, DelimitedFiles, Test, Mmap, SharedArrays, Profile,
Base64, FileWatching, Dates, IterativeEigenSolvers],
clean = false,
doctest = "doctest" in ARGS,
linkcheck = "linkcheck" in ARGS,
Expand Down
1 change: 1 addition & 0 deletions doc/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
* [Shared Arrays](@ref)
* [Base64](@ref)
* [File Events](@ref lib-filewatching)
* [Iterative Eigensolvers](@ref lib-itereigen)

## Developer Documentation

Expand Down
1 change: 1 addition & 0 deletions doc/src/stdlib/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@
* [Shared Arrays](@ref)
* [Base64](@ref)
* [File Events](@ref lib-filewatching)
* [Iterative Eigensolvers](@ref lib-itereigen)
3 changes: 0 additions & 3 deletions doc/src/stdlib/linalg.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,6 @@ Base.transpose
Base.transpose!
Base.adjoint
Base.adjoint!
Base.LinAlg.eigs(::Any)
Base.LinAlg.eigs(::Any, ::Any)
Base.LinAlg.svds
Base.LinAlg.peakflops
Base.LinAlg.stride1
```
Expand Down
7 changes: 7 additions & 0 deletions stdlib/IterativeEigenSolvers/docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# [Iterative Eigensolvers](@id lib-itereigen)

```@docs
IterativeEigenSolvers.eigs(::Any)
IterativeEigenSolvers.eigs(::Any, ::Any)
IterativeEigenSolvers.svds
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

__precompile__(true)

"""
Arnoldi and Lanczos iteration for computing eigenvalues
"""
module IterativeEigenSolvers

using Base.LinAlg: BlasFloat, BlasInt, SVD, checksquare

export eigs, svds

include("arpack.jl")

using .ARPACK

## eigs
Expand Down Expand Up @@ -308,14 +321,14 @@ function SVDAugmented(A::AbstractMatrix{T}) where T
SVDAugmented{Tnew,typeof(Anew)}(Anew)
end

function A_mul_B!(y::StridedVector{T}, A::SVDAugmented{T}, x::StridedVector{T}) where T
function Base.A_mul_B!(y::StridedVector{T}, A::SVDAugmented{T}, x::StridedVector{T}) where T
m, mn = size(A.X, 1), length(x)
A_mul_B!( view(y, 1:m), A.X, view(x, m + 1:mn)) # left singular vector
Ac_mul_B!(view(y, m + 1:mn), A.X, view(x, 1:m)) # right singular vector
return y
end
size(A::SVDAugmented) = ((+)(size(A.X)...), (+)(size(A.X)...))
ishermitian(A::SVDAugmented) = true
Base.size(A::SVDAugmented) = ((+)(size(A.X)...), (+)(size(A.X)...))
Base.ishermitian(A::SVDAugmented) = true

struct AtA_or_AAt{T,S} <: AbstractArray{T, 2}
A::S
Expand All @@ -328,7 +341,7 @@ function AtA_or_AAt(A::AbstractMatrix{T}) where T
AtA_or_AAt{Tnew,typeof(Anew)}(Anew, Vector{Tnew}(uninitialized, max(size(A)...)))
end

function A_mul_B!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) where T
function Base.A_mul_B!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) where T
if size(A.A, 1) >= size(A.A, 2)
A_mul_B!(A.buffer, A.A, x)
return Ac_mul_B!(y, A.A, A.buffer)
Expand All @@ -337,8 +350,8 @@ function A_mul_B!(y::StridedVector{T}, A::AtA_or_AAt{T}, x::StridedVector{T}) wh
return A_mul_B!(y, A.A, A.buffer)
end
end
size(A::AtA_or_AAt) = ntuple(i -> min(size(A.A)...), Val(2))
ishermitian(s::AtA_or_AAt) = true
Base.size(A::AtA_or_AAt) = ntuple(i -> min(size(A.A)...), Val(2))
Base.ishermitian(s::AtA_or_AAt) = true


svds(A::AbstractMatrix{<:BlasFloat}; kwargs...) = _svds(A; kwargs...)
Expand Down Expand Up @@ -433,3 +446,5 @@ function _svds(X; nsv::Int = 6, ritzvec::Bool = true, tol::Float64 = 0.0, maxite
ex[2], ex[3], ex[4], ex[5])
end
end

end # module
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

using IterativeEigenSolvers
using Test

@testset "eigs" begin
Expand Down
6 changes: 3 additions & 3 deletions test/choosetests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,6 @@ function choosetests(choices = [])
"linalg/generic", "linalg/uniformscaling", "linalg/lq",
"linalg/hessenberg", "linalg/rowvector", "linalg/conjarray",
"linalg/blas"]
if Base.USE_GPL_LIBS
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing to me. ARPACK is not GPL-licensed, so why did we only test the Arnoldi stuff if we were using GPL libraries?

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guessing: maybe because it depends on SuiteSparse which is partly GPL?

Copy link
Member Author

@ararslan ararslan Nov 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make sense. I guess I should modify the stdlib tests then to only run Arnoldi when we're okay with using GPL libraries? (i.e. when Base.USE_GPL_LIBS is true)

Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So ARPACK as such doesn't depend on anything in SuiteSparse but the wrappers use factorizations and when the input is sparse, which is the case in some of the tests, then the wrappers use sparse factorizations from SuiteSparse.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the shift and invert solvers need SuiteSparse.

push!(linalgtests, "linalg/arnoldi")
end

if "linalg" in skip_tests
filter!(x -> (x != "linalg" && !(x in linalgtests)), tests)
Expand Down Expand Up @@ -179,6 +176,9 @@ function choosetests(choices = [])
filter!(x -> (x != "Profile"), tests)
end

# The shift and invert solvers need SuiteSparse for sparse input
Base.USE_GPL_LIBS || filter!(x->x != "IterativeEigenSolvers", STDLIBS)

filter!(x -> !(x in skip_tests), tests)

tests, net_on, exit_on_error, seed
Expand Down
5 changes: 3 additions & 2 deletions test/compile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@ try
[:Base, :Core, Foo2_module, FooBase_module, :Main]),
# plus modules included in the system image
Dict(s => Base.module_uuid(Base.root_module(s)) for s in
[:Base64, :CRC32c, :Dates, :DelimitedFiles, :FileWatching, :Mmap,
:Profile, :SharedArrays, :SuiteSparse, :Test]))
[:Base64, :CRC32c, :Dates, :DelimitedFiles, :FileWatching,
:IterativeEigenSolvers, :Mmap, :Profile, :SharedArrays,
:SuiteSparse, :Test]))
@test discard_module.(deps) == deps1

@test current_task()(0x01, 0x4000, 0x30031234) == 2
Expand Down
4 changes: 2 additions & 2 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -535,9 +535,9 @@ let repr = sprint(show, "text/html", methods(f16580))
end

if isempty(Base.GIT_VERSION_INFO.commit)
@test contains(Base.url(first(methods(eigs))),"https://github.com/JuliaLang/julia/tree/v$VERSION/base/linalg/arnoldi.jl#L")
@test contains(Base.url(first(methods(sin))),"https://github.com/JuliaLang/julia/tree/v$VERSION/base/mpfr.jl#L")
else
@test contains(Base.url(first(methods(eigs))),"https://github.com/JuliaLang/julia/tree/$(Base.GIT_VERSION_INFO.commit)/base/linalg/arnoldi.jl#L")
@test contains(Base.url(first(methods(sin))),"https://github.com/JuliaLang/julia/tree/$(Base.GIT_VERSION_INFO.commit)/base/mpfr.jl#L")
end

# print_matrix should be able to handle small and large objects easily, test by
Expand Down