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

Explicit transform for eigs - bugfix generalized eigenvalue problems #27428

Closed
wants to merge 4 commits into from
Closed

Conversation

jarlebring
Copy link
Contributor

@jarlebring jarlebring commented Jun 4, 2018

Here is an attempt to resolve the bug in JuliaLang/LinearAlgebra.jl#488 (or rather the bug reported in the comments in JuliaLang/LinearAlgebra.jl#488). As pointed out in the issue discussion, eigs is currently broken for generalized eigenvalue problems unless B is positive or negative definite, e.g., it normally does not work for non-symmetric B.

The code introduces an explicittransform kwarg which provides the possibility to do shift-and-invert in the julia code, or (as before) let ARPACK do it. If you do shift-and-invert in the julia code the problem does not occur. The explicittransform kwarg defaults to :AUTO which tries to determine if it is a good idea to let ARPACK do the shift-and-invert or do it in julia-code. This way the previous behaviour is accessible to any user using explicittransform=false.

I have tried to keep the code such that the meaning of which and sigma is independent if explicittransform is true or false, which created a bit more if-statements than one might expect, but the advantage is that you get consistent meaning like this:

julia> A=sprandn(100,100,0.1); e1=eye(100,1); A=A+100*e1*e1';

julia> C=I+0.0001*sprandn(100,100,0.1);

julia> B=C*C';  # symm. pos. definite 

julia> λ1=eigs(A,B,explicittransform=false,sigma=1.0)[1]
6-element Array{Complex{Float64},1}:
0.8853783560528526 - 0.2251061711212125im
0.8853783560528526 + 0.2251061711212125im
1.4198361576177376 + 0.0im               
0.5786082353083483 - 0.5069352320198903im
0.5786082353083483 + 0.5069352320198903im
1.6872265416932886 + 0.0im               

julia> λ2=eigs(A,B,explicittransform=true,sigma=1.0)[1]
6-element Array{Complex{Float64},1}:
0.8853783560528521 + 0.2251061711212136im
0.8853783560528521 - 0.2251061711212136im
1.4198361576177394 + 0.0im               
0.5786082353083479 + 0.5069352320198891im
0.5786082353083479 - 0.5069352320198891im
1.6872265416932901 + 0.0im               

After hopefully some discussion on this here I can add it to the function description.

@jarlebring
Copy link
Contributor Author

jarlebring commented Jun 4, 2018

I forgot explanation: I had to change

matvecA!(y, x) = mul!(y, A, x)

to

matvecA! = (y, x) -> mul!(y, A, x)

because I wanted to change the function at a later point. Maybe someone knows if this change can have implications on performance?

@fredrikekre fredrikekre requested a review from andreasnoack June 4, 2018 22:45
@fredrikekre fredrikekre added the linear algebra Linear algebra label Jun 4, 2018
@jarlebring
Copy link
Contributor Author

jarlebring commented Jun 5, 2018

It seems it passes all unit tests except this:

srand(127) 
n = 10
k = 3
A = randn(n,n); A = A'A
B = randn(n,k); B = B*B'
@test sort(eigs(A, B, nev = k, sigma = 1.0)[1])  sort(eigvals(A, B)[1:k])

It fails when it tries to sort complex numbers. With explicittransformation=true we get eltype Complex128 and with explicittransformation=false we get eltype Float64.

It can be easily "fixed" by changing the test to

@test sort(eigs(A, B, nev = k, sigma = 1.0,explicittransform=false)[1])  sort(eigvals(A, B)[1:k])

I do realize that returning different types based on kwarg-values is text-book type instability. The only fix I can think of is to take another parameter to eigs is a bit intrusive. Something like this:

eigs(A,B;params)=_eigs(Complex128,A,B;params...);
eigs(T,A,B;params)=_eigs(T,A,B;params...);
function _eigs{T}(::Type{T},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, explicittransform=:AUTO)
...

Not sure how severe is this problem is. Ideas appreciated.

@haampie
Copy link
Contributor

haampie commented Jun 5, 2018

eigs is already having this type instability due to the ritzvec = true/false parameter, so I don't think it's a real problem.

@jarlebring
Copy link
Contributor Author

Ah. Yes indeed. Also, the older discussion in JuliaLang/LinearAlgebra.jl#279 suggests that making it type stable is non-trivial.

@andreasnoack andreasnoack self-assigned this Jun 10, 2018
@andreasnoack andreasnoack reopened this Jun 11, 2018
@StefanKarpinski
Copy link
Member

If the values of this argument are true, false and :AUTO it seems like it would perhaps be better to do true, false and nothing where nothing chooses automatically?

@@ -69,9 +69,11 @@ 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)
ritzvec::Bool=true, explicittransform=nothing)
Copy link
Member

Choose a reason for hiding this comment

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

Slightly better to put a Union{Bool, Nothing} type annotation on this then 😀

@jarlebring
Copy link
Contributor Author

Sounds better indeed. Should be fixed now.

I'm not so experienced in contributing in this way, want me to add tests? Squash commits?

@andreasnoack
Copy link
Member

@jarlebring Thanks for preparing this PR Sorry for the lag of response. It's on my todo but I've had to look into other tasks before getting to this. Hopefully, I'll find the time for a review later this week.

@andreasnoack
Copy link
Member

@jarlebring As you might have noticed, we have moved ARPACK bindings to Arpack.jl (which partly has contributed to the delay in reviewing this PR) such that developement of our ARPACK wrappers won't be tied to the developement cycles of the main repo. Would you mind moving this PR to Arpack.jl instead. Then we should be able to merge it shortly.

@jarlebring
Copy link
Contributor Author

Sounds good. See new PR in JuliaLinearAlgebra. Hope I understood you correctly.

@jarlebring jarlebring closed this Jun 20, 2018
stevengj pushed a commit to stevengj/Arpack.jl that referenced this pull request Sep 23, 2020
ViralBShah pushed a commit to JuliaLinearAlgebra/Arpack.jl that referenced this pull request Dec 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
linear algebra Linear algebra
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants