Skip to content

Conversation

@amanp10
Copy link
Contributor

@amanp10 amanp10 commented Feb 4, 2017

Fixes: #6430
unit tests and warnings added along with the changes.

Copy link
Member

@perimosocordiae perimosocordiae left a comment

Choose a reason for hiding this comment

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

This PR broke the test_arpack.test_eigen_bad_kwargs test.

My other comments are in-line.

eigsh(A, k=4)
eigsh(A, k=5)


Copy link
Member

Choose a reason for hiding this comment

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

Each of these tests should check the returned values of eigs/eigsh for correctness.

if k >= n:
import warnings
warnings.warn('k greater than/equal to the order of the square '
'matrix. Using scipy.linalg.eig instead.')
Copy link
Member

Choose a reason for hiding this comment

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

This should use a SparseEfficiencyWarning rather than a generic UserWarning.

import warnings
warnings.warn('k greater than/equal to the order of the square '
'matrix. Using scipy.linalg.eig instead.')
if return_eigenvectors is True:
Copy link
Member

Choose a reason for hiding this comment

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

The is True isn't needed here.

if k >= n-1:
import warnings
warnings.warn('k greater than/equal to N - 1 . '
'Using scipy.linalg.eig instead.')
Copy link
Member

Choose a reason for hiding this comment

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

This warning doesn't explain what N is.

@amanp10
Copy link
Contributor Author

amanp10 commented Feb 9, 2017

The reason test_arpack.test_eigen_bad_kwargs broke was because now k more than N-1 wont raise any ValueError instead it would go on to eig. Earlier, since k=6 is default, ValueError was raised. I think test_arpack.test_eigen_bad_kwargs needs to be modified little.

@pv
Copy link
Member

pv commented Feb 9, 2017

@amanp10: correct, test_eigen_bad_kwargs should probably be modified to use a larger matrix.

@amanp10
Copy link
Contributor Author

amanp10 commented Feb 10, 2017

@perimosocordiae please have a look.

Copy link
Member

@perimosocordiae perimosocordiae left a comment

Choose a reason for hiding this comment

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

Looks fine to me now.

This may have backwards-compatibility implications, though, so it should probably get a mention in the release notes.

if return_eigenvectors:
return eig(A.todense())
else:
return eig(A.todense(), right=False)
Copy link
Member

Choose a reason for hiding this comment

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

These can probably be condensed into one return:

return eig(A.todense(), right=return_eigenvectors)

(Same for the similar lines below.)

@amanp10
Copy link
Contributor Author

amanp10 commented Feb 11, 2017

Am I supposed to mention it in the release notes or the core-devs do it?

@pv
Copy link
Member

pv commented Feb 11, 2017

@amanp10: note that you should not do git merge upstream/master or git pull upstream/master etc in pull requests. (If there are conflicts, the PR should be rebased on master instead of master being merged to the PR.)

@amanp10
Copy link
Contributor Author

amanp10 commented Feb 11, 2017

@pv I will take care from now on. Thanks for pointing out.

warnings.warn('k greater than/equal to N - 1 for N * N square matrix. '
'Using scipy.linalg.eig instead.',
SparseEfficiencyWarning)
return eig(A.todense(), right=return_eigenvectors)
Copy link
Member

Choose a reason for hiding this comment

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

This should also check if M is given, and if yes, solve the generalized eigenvalue problem. (Add also a test.)

Additionally A may be a LinearOperator or a dense matrix, which don't have a todense method.

@rgommers rgommers added good first issue Good topic for first contributor pull requests, with a relatively straightforward solution scipy.sparse.linalg labels Feb 16, 2017
@pv pv added the needs-work Items that are pending response from the author label Feb 18, 2017
@amanp10
Copy link
Contributor Author

amanp10 commented Feb 20, 2017

@pv Sorry for the late commit. I got busy with class tests. Please have a look

if not isdense(A):
A = A.todense()

return eig(A, b=M, right=return_eigenvectors)
Copy link
Member

@perimosocordiae perimosocordiae Feb 20, 2017

Choose a reason for hiding this comment

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

This should be eigh, right?
My bad, this is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the mistake, I will correct it.

@amanp10
Copy link
Contributor Author

amanp10 commented Mar 2, 2017

I was wondering if it would be necessary to add tests for complex or complex-hermitian matrix as well?


n = A.shape[0]

if k >= n - 1:
Copy link
Member

Choose a reason for hiding this comment

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

This condition should be run after the k <= 0 or k >= n check.

import warnings
warnings.warn('k greater than/equal to N - 1 for N * N square matrix. '
'Using scipy.linalg.eig instead.',
SparseEfficiencyWarning)
Copy link
Member

Choose a reason for hiding this comment

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

A SparseEfficiencyWarning doesn't make sense if A isn't sparse.

raise ValueError("'M' cannot be a LinearOperator since"
"scipy.linalg.eig is being used.")
if not isdense(A):
A = A.todense()
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer raising an error if A is sparse, with a hint to call .toarray() first if that's actually what the user wants.

Copy link
Contributor Author

@amanp10 amanp10 Aug 24, 2017

Choose a reason for hiding this comment

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

I think the docs need to be changed as they mention A as A : ndarray, sparse matrix or LinearOperator. Or should we let it be with errors and warnings wherever necessary?

Copy link
Member

Choose a reason for hiding this comment

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

No, we still need to support all three input types. I'm suggesting that be behavior for non-ndarray types (spmatrix, LinearOperator) remain as it was before this PR, but with an informative error message so that the user knows how to proceed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay. I get it.

if k >= n:
import warnings
warnings.warn('k greater than/equal to N for N * N square matrix. '
'Using scipy.linalg.eig instead.',
Copy link
Member

Choose a reason for hiding this comment

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

scipy.linalg.eigh, here and in the error messages below.

"scipy.linalg.eig is being used.")
if isinstance(M, LinearOperator):
raise ValueError("'M' cannot be a LinearOperator since"
"scipy.linalg.eig is being used.")
Copy link
Member

Choose a reason for hiding this comment

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

These errors should explain that k >= n is why we can't use eigsh here.

j = np.random.randint(N, size=N * N // 2)
M[i,j] = 0

M = 0.5 * (M + M.T) # Make M symmetric
Copy link
Member

Choose a reason for hiding this comment

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

This is likely to destroy whatever sparsity we just created. I'd symmetrize first, then set (symmetric) zeros.

if pos_definite:
M = M + N * np.eye(N)

return M
Copy link
Member

Choose a reason for hiding this comment

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

Need to create an actual sparse matrix if sparse=True.

raise ValueError("k=%d must be greater than 0." % (k, n - 1))

if k >= n - 1:
if not isdense(A):
Copy link
Member

Choose a reason for hiding this comment

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

Why not use if issparse(A) here?

from scipy.linalg import svd, hilbert

from scipy._lib._gcutils import assert_deallocated
#from warnings import catch_warnings, simplefilter
Copy link
Member

Choose a reason for hiding this comment

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

Remove this line, please.

i = np.random.randint(N, size=N * N // 2)
j = np.random.randint(N, size=N * N // 2)
M[i, j] = 0
M = M + Id
Copy link
Member

Choose a reason for hiding this comment

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

M += Id

j = np.random.randint(N, size=N * N // 2)
M[i, j] = 0

return M
Copy link
Member

Choose a reason for hiding this comment

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

if sparse:
    M = scipy.sparse.csr_matrix(M)
return M

A = generate_matrix(4, sparse=False)
M1 = np.random.random((4, 4))
M2 = generate_matrix(4, sparse=True)
M3 = aslinearoperator(M1)
Copy link
Member

Choose a reason for hiding this comment

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

Might be clearer to use M_dense, M_sparse, and M_linop.

raise ValueError("k=%d must be between 1 and ndim(A)-1=%d"
% (k, n - 1))
if k <= 0:
raise ValueError("k=%d must be greater than 0." % (k, n - 1))
Copy link
Member

Choose a reason for hiding this comment

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

You're giving too many values to the format string here. We aren't using n - 1 anymore.

"A with k >= N - 1.")
if isinstance(M, LinearOperator):
raise TypeError("Cannot use scipy.linalg.eig for LinearOperator "
"M with k >= N - 1.")
Copy link
Member

Choose a reason for hiding this comment

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

This LinearOperator checks need to happen before the warning.

Copy link
Contributor Author

@amanp10 amanp10 Oct 8, 2017

Choose a reason for hiding this comment

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

I think we should inform the user that we are using or trying to use scipy.linalg.eig right after the check k >= n(or k >= n - 1). Or maybe we can put it in the docs somewhere.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I see what you're saying here. (Sorry for the long wait!) Can you move the warning up before the TypeError checks here? And maybe have it say "Attempting to use" instead of "Using"?

@amanp10
Copy link
Contributor Author

amanp10 commented Dec 3, 2017

I need some help here. I cant figure out why the build is failing.

@andyfaff
Copy link
Contributor

andyfaff commented Dec 3, 2017

THe build is failing due to issues we've been having with our OSX image on TravisCI. I think the problem is unrelated to this PR.

@amanp10
Copy link
Contributor Author

amanp10 commented Dec 3, 2017

@perimosocordiae I have made the changes please have a look.

@perimosocordiae
Copy link
Member

Looks good now, thanks @amanp10! I'll wait a bit to let others comment before merging.

@amanp10
Copy link
Contributor Author

amanp10 commented Dec 4, 2017

Thank you for all the reviews.

raise TypeError("Cannot use scipy.linalg.eig for LinearOperator "
"M with k >= N - 1.")

import warnings
Copy link
Member

Choose a reason for hiding this comment

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

You just need to import warnings module at the top of the file and you can use it in any function. Also with

from .misc import LinAlgWarning

you can raise a LinAlgWarning which I guess is more relevant instead of a UserWarning. Also you already know the values of k and N so the message can use those values

    warnings.warn("{0} >= {1} for {1}x{1} square matrix. "
                  "Using scipy.linalg.eigh instead.".format(k, N),
                  LinAlgWarning, stacklevel=3)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I cant find LinAlgWarning because this branch has not been updated to v1.1. Should I merge this branch with the latest master branch to get LinAlgWarning?

Copy link
Member

Choose a reason for hiding this comment

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

Then I guess the regular RuntimeWarning would suffice. At some point we will sweep all the warnings anyhow.

raise TypeError("Cannot use scipy.linalg.eigh for LinearOperator "
"M with k >= N.")

import warnings
Copy link
Member

Choose a reason for hiding this comment

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

same import issue as above

@ilayn
Copy link
Member

ilayn commented Jan 20, 2018

@pv @perimosocordiae Any reservations left for this PR?

@perimosocordiae
Copy link
Member

Sorry for the extreme slowness on my part. I left one comment, and there appears to be a merge conflict to resolve, but after those are handled I will definitely merge this quickly.

@amanp10
Copy link
Contributor Author

amanp10 commented Mar 8, 2018

I am unable to understand why the Travis-Ci build is failing. Need some help here.

@rgommers
Copy link
Member

rgommers commented Mar 8, 2018

Just ignore those TravisCI failures, that's due to some issues unrelated to this PR

@perimosocordiae perimosocordiae merged commit 5a6fad5 into scipy:master Mar 9, 2018
@perimosocordiae
Copy link
Member

Merged, at long last. Thanks, @amanp10 !

@amanp10
Copy link
Contributor Author

amanp10 commented Mar 10, 2018

I am happy I contributed something.

@amanp10 amanp10 deleted the Branch2 branch March 10, 2018 05:09
adbugger pushed a commit to adbugger/scipy that referenced this pull request Mar 11, 2018
ENH: scipy.linalg.eigsh cannot get all eigenvalues
@pv pv added this to the 1.1.0 milestone Mar 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

good first issue Good topic for first contributor pull requests, with a relatively straightforward solution needs-work Items that are pending response from the author scipy.sparse.linalg

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants