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

BUG: Have norm cast non-floating point arrays to 64-bit float arrays #7088

Merged
merged 4 commits into from
Jan 23, 2016

Conversation

jakirkham
Copy link
Contributor

Fixes #5626

Simply ensures that non-floating type arrays passed to norm get cast to some form of float.

@@ -2112,6 +2112,9 @@ def norm(x, ord=None, axis=None, keepdims=False):
"""
x = asarray(x)

if not issubclass(x.dtype.dtype, floating):
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like a copy-and-double-paste typo. The tests are failing here. Did you mean x.dtype?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, sorry, was on autopilot. Fixed. Meant x.dtype.type.

@@ -2112,6 +2112,9 @@ def norm(x, ord=None, axis=None, keepdims=False):
"""
x = asarray(x)

if not issubclass(x.dtype.type, floating):
Copy link
Contributor

Choose a reason for hiding this comment

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

One more thing. Did you mean either float or numpy.float? This is the new point of failure in the tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope meant floating, but it wasn't imported. Just fixed as you were typing. :) See above.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is the right check. Typically, we handle this by adding 0.0 to the result, which preserves inexact types and respects complex. Note

In [10]: a = array([1,2,3], complex)

In [11]: issubclass(a.dtype.type, floating)
Out[11]: False

You can also do

In [13]: issubdtype(a.dtype, np.inexact)
Out[13]: True

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, you want to check complexfloating too. Sure, sorry wasn't thinking about complex.

@@ -2112,6 +2112,9 @@ def norm(x, ord=None, axis=None, keepdims=False):
"""
x = asarray(x)

if not issubclass(x.dtype.type, floating):
x = x.astype(float)
Copy link
Contributor

Choose a reason for hiding this comment

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

On a related note, should this be np.float or am I misreading?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

np.float is just an alias to float (i.e. np.float is float will be True). In fact, I believe those aliases are planned to be removed, but I can't find the issue right now.

@jakirkham
Copy link
Contributor Author

Should we try to fix np.dot too?

@jakirkham
Copy link
Contributor Author

So, ord=0 will still return int currently. Do we want to make it float there too? This would be simple, but am unsure as to whether this is a good idea.

@charris
Copy link
Member

charris commented Jan 21, 2016

Hmm, interesting question. Consistency would say "yes", so I tend that way, but let's see if @pv has an opinion, it is his addition.

@@ -2112,6 +2112,9 @@ def norm(x, ord=None, axis=None, keepdims=False):
"""
x = asarray(x)
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 just add 0.0 here.

Copy link
Member

Choose a reason for hiding this comment

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

That is x = asarray(x) + 0.0. it's a bit ugly, but there you go. I had a proposal to add a mintype keyword to asarray that would also have solved this problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Personally, I'm not a fan. I think that adding or multiplying is performing an otherwise needless element operation especially for arrays of the right type. Also, if we need to cast to a preferred type, we should just do that explicitly.

@jakirkham
Copy link
Contributor Author

Just to clarify the conflict I see with ord=0.

From the documentation side, it says it returns ndarray or float so this change would follow with that.
However, the examples return ints for ord=0. So, we would be in disagreement there.

From a mathematical standpoint, we know ord=0 will always be a positive semi-definite whole number. So, it seems unnecessary to make it a float. However, our experience with integer rollover tells us otherwise.

@charris
Copy link
Member

charris commented Jan 22, 2016

LGTM, could you put some test together to check the types? Can make some simple for loops to cycle through the types and norms and check the result type.

@jakirkham jakirkham force-pushed the cast_float_linalg branch 7 times, most recently from 49dfdc5 to 1a6ac8b Compare January 22, 2016 18:31
@jakirkham
Copy link
Contributor Author

Ok, I think these work. There are a few cases where things might get cast up or converted from complex to float so it got a bit messy, but these check out for me thus far.

@jakirkham
Copy link
Contributor Author

Should we try folding the exact and inexact tests together? I probably can do this by reusing the inexact case for the exact case.

@jakirkham
Copy link
Contributor Author

Also, just as an FYI, we have a serious storm front forecasted to hit our area in about 2hrs so there is a chance I might lose power/internet when or soon after it hits. If you need me to clean up anything before then, please let me know as soon as you can. Otherwise, I may have to let this sit for a few days depending on conditions.

@charris
Copy link
Member

charris commented Jan 22, 2016

If you disappear for a few snow days and the PR needs some fixes, I'll pull it down and do the fix. To avoid snow, buy a snow blower, it seems to affect the weather. Winters here have been milder ever since I bought mine...

for each_inexact_types in all_types:
at = a.astype(each_inexact_types)

n = norm(at, -np.inf)
Copy link
Member

Choose a reason for hiding this comment

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

Just to note that it is unusual to use any of ijklmn for floats. That goes back to the implicit typing of early Fortran where variables beginning with those letters were integers.

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 suppose. Though I do see some others doing the same thing in this file ( https://github.com/numpy/numpy/blob/master/numpy/linalg/tests/test_linalg.py#L935 ).

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 have renamed all the ns to ans.

Copy link
Member

Choose a reason for hiding this comment

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

I expect the knee jerk reaction to 'ijklmn' will eventually pass with my generation. Fortran bugs due to incorrectly typed variables were subtle and frustrating. Explicit typing in Fortran was a lifesaver when it arrived, right up there with the arrival of prototypes in C.

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 guess I am more of a stickler for i, j, and sometimes k being ints . The rest of them sort of fall of the map for me. Since learning Python, I find myself using itertools.product for any complicated nested for loop. Sometimes use l for lists that I can't think of a better name for.

@jakirkham
Copy link
Contributor Author

BTW, as I have rebased and forced pushed a bunch while cleaning this up, it appears the AppVeyor queue has really blocked up with pointless jobs from old version of this PR. I think all but the most recent one can be canceled.

@charris
Copy link
Member

charris commented Jan 22, 2016

LGTM. I'm going to clear out a bunch of the AppVeyor tests that are queued up, otherwise we will wait forever for test completion.

@jakirkham
Copy link
Contributor Author

Sounds good. Looks like the 1.11.0 list is basically done. When are you thinking of tagging the release?

@charris
Copy link
Member

charris commented Jan 23, 2016

Sometime this weekend, maybe tomorrow.

@jakirkham
Copy link
Contributor Author

Cool. One other side question. Do the doctests get run as part of the testing suite and, if not, should they?

@charris
Copy link
Member

charris commented Jan 23, 2016

No, they don't. It comes up for discussion now and then, the last time being last summer. I think you can find it the mailing list archives. We don't use doctests for testing because they are hard to maintain and difficult to use for many tests, they mostly serve as pedagogical examples. So while it doesn't hurt to keep doctests up to date -- we would not refuse a PR fixing a doctest -- it isn't a high priority.

charris added a commit that referenced this pull request Jan 23, 2016
BUG: Have `norm` cast non-floating point arrays to 64-bit float arrays
@charris charris merged commit 66156a0 into numpy:master Jan 23, 2016
@charris
Copy link
Member

charris commented Jan 23, 2016

Thanks @jakirkham .

@jakirkham
Copy link
Contributor Author

Thanks @charris. I'll backport it.

@jakirkham
Copy link
Contributor Author

Backported to 1.11.x in this PR ( #7098 ).

@charris
Copy link
Member

charris commented Jan 23, 2016

For future reference, your commit messages lack line breaks. Commit messages should have hard line breaks and line length <=72, blank line after first link commit summary.

@jakirkham
Copy link
Contributor Author

Thanks, I'll keep that in mind for the future.

@charris charris removed this from the 1.11.0 release milestone Jan 23, 2016
@mgeier
Copy link
Contributor

mgeier commented Apr 27, 2016

This introduced a regression, see #7575.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants