Skip to content

BUG: Always return a real dtype from linalg.cond (gh-18304) #29333

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

broesler
Copy link

@broesler broesler commented Jul 7, 2025

Addresses gh-18304.

The condition number of a matrix is the product of two norms, which are
always non-negative and real-valued, so the condition number itself
should be non-negative and real-valued. This commit returns the proper
real dtype from linalg.cond, and includes tests for the condition
number of a complex matrix in various norms.

The existing docstring for linalg.cond already states that the return value is
either a float or inf, so the function behavior is now consistent with the
docstring.

Addresses numpygh-18304.

The condition number of a matrix is the product of two norms, which are
always non-negative and real-valued, so the condition number itself
should be non-negative and real-valued. This commit returns the proper
real dtype from `linalg.cond`, and includes tests for the condition
number of a complex matrix in various norms.
return r
# Return the absolute value, since the condition number is
# always a non-negative real number.
return abs(r)
Copy link
Member

Choose a reason for hiding this comment

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

Thanls, I am sure it's correct, but I do feel it should probably be more targeted to where the complex number comes from here.

This commit addresses a reviewer comment on the blanket application of
`abs(r)`. It specifically ensures the return type of complex-valued
matrices will be the corresponding real type.
Copy link
Member

@seberg seberg left a comment

Choose a reason for hiding this comment

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

Thanks, LGTM. I do wonder if we should add a release note, since it is a subtle fix, but it seems pretty hard to run into issues due to not getting a complex value.

@@ -2011,6 +2011,7 @@ def cond(x, p=None):
# contain nans in the entries where inversion failed.
_assert_stacked_square(x)
t, result_t = _commonType(x)
result_t = _realType(result_t) # condition number is always real
signature = 'D->D' if isComplexType(t) else 'd->d'
with errstate(all='ignore'):
invx = _umath_linalg.inv(x, signature=signature)
Copy link
Member

Choose a reason for hiding this comment

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

So, I think this is fine. Your other comment (deleted now) is not wrong, in that it would be fine to cast invx to the original result_t to achieve the right thing.
(Norm might in some paths end up casting back and forth then, but it would work too.)

@broesler
Copy link
Author

broesler commented Jul 8, 2025

I agree that a release note is probably not needed. There is functionally no difference, since the imaginary part was always 0 anyway. There are no member functions that differ between np.single and np.csingle (or double, respectively). I'm not sure if there are any numpy functions that would balk at getting a float vs. a complex number.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Pending authors' response
Development

Successfully merging this pull request may close these issues.

2 participants