-
Notifications
You must be signed in to change notification settings - Fork 2
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
Overhaul SVDS input validation and test suite #20
Conversation
There was never a guarantee that solver=None was supported; solver='arpack' has always been the default value. No need to carry around this baggage.
…lar_vectors of svds
…r_vectors of svds
If specified, must satistify ``k + 1 < ncv < N``; ``ncv > 2*k`` is | ||
recommended. | ||
If specified, must satistify ``k + 1 < ncv < min(M, N)``; ``ncv > 2*k`` | ||
is recommended. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seemed to be wrong. I let's double check master before changing this.
if k <= 0 or k >= min(n, m): | ||
raise ValueError("k must be between 1 and min(A.shape), k=%d" % k) | ||
|
||
if isinstance(A, LinearOperator): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just converted everything to a LinearOperator
in the input validation so we can get rid of this branching.
@@ -1,8 +1,10 @@ | |||
import re |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up basically rewriting all this. There were just a lot of holes, and it didn't make sense to leave the existing tests and add new ones that were more comprehensive.
@@ -823,4 +823,5 @@ def aslinearoperator(A): | |||
rmatmat=rmatmat, dtype=dtype) | |||
|
|||
else: | |||
raise TypeError('type not understood') | |||
A = np.atleast_2d(np.asarray(A)) | |||
return MatrixLinearOperator(A) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See scipygh-14299
scipy/sparse/linalg/eigen/_svds.py
Outdated
|
||
# input validation/standardization for `maxiter` | ||
if maxiter is not None and (int(maxiter) != maxiter or maxiter <= 0): | ||
message = "`maxiter` must be a non-negative integer." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"must be a positive integer"
|
||
largest = (which == 'LM') | ||
n, m = A.shape |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this where svds
doesn't match docs? I would have expected m, n = A.shape
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, surprisingly. Despite flipping n, m
between code and documentation, everything is right except for the inequality strictness being swapped in the documentation.
I think I'm done with this PR. With these changes and any other cleanups you want to do, I think we're about ready to open a PR on the main repo. When we do, there are a few things I'd like to bring to the attention of reviewers there:
|
Some work is not complete:
I haven't looked closely at the accuracy testsUpdate: I confirmed that the basic test makes sense. I refactored it to cut lines, add cases, and strengthen the checks. I haven't looked carefully attest_svd_linop
. I can't tell if it's an important addition or not, so rather than improving it or cutting it, I just left it alone. One thing that I think is missing is an accuracy test for a real-world, sparse matrix, but actually that is already in thesvdp
test suite, so I don't think I'll add it here.I haven't looked closely at the edge casesUpdate: I confirmed that the edge case tests make sense and refactored them to cut lines. Note that we're still not perfect here, especially with PROPACK.There is no support for the PROPACK-specific options.Update: save this for follow-up work.There are a few kinks to work out:
maxiter
for PROPACK should be investigated more carefully. I think you had hooked it up tomaxiter
ofsvdp
, but that is only used ifirl_mode
isTrue
, so it seemed more appropriate to hook it up tokmax
which is described as "Maximal number of iterations...". However, there is a requirement thatkmax >= k
that is more stringent than the usual requirements onmaxiter
. If we want to keep it this way, we should adjust the input validation test forsolver='propack'
. But I don't really know what's going on under the hood, so we should talk about this.ForUpdate: fixed.arpack
andlobpcg
,v0
is supposed to be of lengthmin(A.shape)
. This is not the case for PROPACK, and this is causing failure of one of the IV tests and alsotest_svd_linop
. I think we can change the documentation and IV for PROPACK and this will fix the tests.The behavior ofUpdate: PROPACK now respects thereturn_singular_value
is really restrictive for PROPACK; it doesn't care about the shape of the matrix when you tell it to not calculate some of the eigenvectors. Currently I am enforcing the shape restrictions of ARPACK/LOBPCG, but that should be reconsidered.return_singular_value
option regardless of matrix shape.PROPACK is inaccurate whenUpdate: this was fixed by changing the random state.return_singular_vectors
isFALSE
in one test case. Weird.The documentation ofreturn_singular_value
did not reflect the behavior of ARPACK and LOBPCG after all. I think the inequalities on the shapes need to switch which is strict and which isn't to reflect the actual behavior.AFAIKUpdate: done.propack
can handlek=min(A.shape)
; it does not need to be a strict inequality. This requirement of the IV should be relaxed.I addedUpdate: added for the others, but peculiarities of existing behavior needs to be documented (or we should drop the requirement that the outputs must be exactly the same as they were before.)random_state
keyword support for PROPACK; I need to include it for the others.v0
parameter.I am continually tempted to abandon
svds
and just expose PROPACK in a function with the interface that PROPACK wants. But I figure I'll do the harder thing first - force PROPACK into SVDS - and then splitting it into its own function, if desired, would be very easy.