-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
ENH: Wrap LAPACK's dsytrd #7780
Conversation
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 think once the <prefix>
part is fixed this can build and the tests can be evaluated properly. One thing to look out for is not to cause segfaults even when used inappropriately. Recently we had a case with supplying np.empty((0,0))
was causing segfaults so better add it and possibly others if any, to the tests.
scipy/linalg/flapack.pyf.src
Outdated
integer intent(in) :: n | ||
integer optional,intent(in),check(lower==0||lower==1) :: lower = 0 | ||
|
||
integer intent(hide),depend(n) :: lda=n |
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.
Haven't checked if lwork=-1
causes a shortcut in the Fortran source, but still better to keep lda = MAX(n,1)
to be on the safe side as it causes trouble on the Fortran side with zero-sized arrays. n=0
OK for LAPACK for which they have often a safeguard as a convention but lda=0
is not.
scipy/linalg/flapack.pyf.src
Outdated
callstatement (*f2py_func)((lower?"L":"U"),&n,a,&lda,d,e,tau,work,&lwork,&info); | ||
callprotoargument char*,int*,<ctype2>*,int*,<ctype2>*,<ctype2>*,<ctype2>*,<ctype2>*,int*,int* | ||
|
||
integer intent(hide),depend(a) :: lda=shape(a,0) |
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.
Use lda = MAX(shape(a,0),1)
to avoid lda=0
scipy/linalg/tests/test_lapack.py
Outdated
A = np.random.normal(size=(n, n)) | ||
A += A.T | ||
|
||
sytrd, sytrd_lwork = get_lapack_funcs(('sytrd', 'sytrd_lwork')) |
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.
You would add the array you want to get the LAPACK routine for as get_lapack_funcs(('sytrd', 'sytrd_lwork'), (A,))
such that d
is selected. Same should also test for s
flavor with a float32
array.
scipy/linalg/flapack.pyf.src
Outdated
<ftype2> intent(out) :: work | ||
integer intent(hide) :: lwork = -1 | ||
integer intent(out) :: info | ||
end subroutine <prefix>sytrd_lwork |
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 needs to be <prefix2>
instead.
scipy/linalg/tests/test_lapack.py
Outdated
|
||
# query lwork | ||
lwork, info = sytrd_lwork(n) | ||
assert info == 0 |
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.
Naked assert
s are not allowed. You can use assert_equal
from numpy.testing
module
scipy/linalg/tests/test_lapack.py
Outdated
assert info == 0 | ||
|
||
data, d, e, tau, info = sytrd(A, lwork) | ||
assert info == 0 |
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.
Same comment about assert
scipy/linalg/tests/test_lapack.py
Outdated
np.random.seed(42) | ||
n = 3 | ||
A = np.random.normal(size=(n, n)) | ||
A += A.T |
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.
Inplace addition of overlapping arrays is undefined in Numpy < 1.13
@ilayn When supplying a
that sounds pretty reasonable, right? |
I'm going to need some help here. The error message is
and really |
What you can do is to drop into a pdb session (insert |
@ev-br How to I execute just the LAPACK tests locally? (Otherwise it always takes half an hour.) |
|
@everyone Tests are passing now. Anything else for me to do? |
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've added some minor comments. I think when they are addressed, this is good to go.
scipy/linalg/flapack.pyf.src
Outdated
integer intent(hide),depend(a) :: n=shape(a,1) | ||
integer optional,intent(in),check(lower==0||lower==1) :: lower = 0 | ||
|
||
<ftype2> dimension(lda,n),intent(in,out,copy,out=c) :: 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.
This needs a squareness check before LAPACK chews it so it is best if we intervene
<ftype2> dimension(lda,n),check(shape(a,0)==shape(a,1)),intent(in,out,copy,out=c) :: a
scipy/linalg/flapack.pyf.src
Outdated
<ftype2> dimension(n),intent(out),depend(n) :: d | ||
<ftype2> dimension(n-1),intent(out),depend(n) :: e | ||
<ftype2> dimension(n-1),intent(out),depend(n) :: tau | ||
integer intent(in),optional,depend(n),check(lwork>=MAX(n,1)) :: lwork = MAX(n,1) |
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.
Lwork is not needed to be n
or higher. It just needs to be greater than or equal to 1. For this you can keep the default but the check needs to be as
integer intent(in),optional,depend(n),check(lwork>=1||lwork==-1) :: lwork = MAX(n,1)
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.
Here we already define sytrd_lwork
for -1 query, but some people do it manually so better to keep it general.
scipy/linalg/tests/test_lapack.py
Outdated
def test_sytrd(self): | ||
for dtype in REAL_DTYPES: | ||
# "random" symmetric matrix | ||
A = np.array([ |
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.
If you create A
via
n = 3
A = np.zeros((n, n), dtype=dtype)
A[np.triu_indices_from(A)] = np.arange(1, 2*n+1, dtype=dtype)
(or typing out manually if you wish), you can quickly test for lower=1
behavior for n
of your choice since it will give the matrix and it's diagonal back together with zero arrays for a diagonal matrix. Then it can continue with lower=0
case for the precise calculation.
The comment can be worded as # some upper triangular array
to avoid confusion about the randomness too.
scipy/linalg/tests/test_lapack.py
Outdated
# disable rtol here since some values in QTAQ and T are very close | ||
# to 0. | ||
assert_allclose(QTAQ, T, atol=5*np.finfo(dtype).eps, rtol=1.0) | ||
return |
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 think we don't need this return
here, no?
I have just seen your final remark in the original PR comment. Let's not waste this opportunity to wrap the complex versions. This should do the (C/Z)HETRD versions
together with their definitions in the
It would be great if you can extend the test to cover these too while we are at it. |
What does this do on Having fixed this type of bug in numpy, the error is typically that it should be |
@eric-wieser Yes it produces an error (also for 1x1 array). Since f2py needs to allocate arrays at the outset, the subdiagonals needs to be provided and in these cases subdiagonal sizes are -1 and 0 respectively which is problematic in both cases so it trips at the f2py
In the other routines, we have also fixed a similar bug recently with the same conclusion (#7633) |
Doesn't seem like (1,1) should be a problem to me - isn't (0,) a valid size? I see your point about (0,0) though. Either way, it might be nice to add tests for these cases. |
I agree. I'll check it out tomorrow. |
The error that is produced when dealing with a 1x1 array is
I don't understand what variable gets |
Okay, so it's apparently about the arrays
(representing the super/subdiagonal, |
Alright, so this appears to be a NumPy bug (numpy/numpy#9617). It wouldn't make much sense to add a test for |
I'd maybe argue for a |
I've added a TODO note (although I'd consider this an upstream issue). |
Is it going to be backported? |
Probably a question to ask on the numpy side. Either way, no change is required on scipy for this to work properly. |
thanks, lgtm. I don't see a nice way to support the 1x1 case before f2py supports size-0 arrays. |
This PR adds the wrapper for LAPACK's dsytrd, a routine that takes a real symmetric matrix A and transforms it to a tridiagonal matrix by an orthogonal similarity tranformation
With test.
I would have wrapped its complex variant
*HETRD
as well, but I didn't know how to map the complex type<ctype2c>
to its corresponding real type in the wrapper code. (HETRD
transforms a complex Hermitian matrix to a real symmetric tridiagonal matrix.)Fixes #7775.