Skip to content

np.max() doesn't behave properly for ndarray subclasses that define __array_ufunc__ #9102

Closed

Description

@ngoldbaum

Take the following example:

import numpy as np

class MyArr(np.ndarray):
    def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
        func = getattr(ufunc, method)
        inp = [i.view(np.ndarray) for i in inputs]
        return func(*inp, **kwargs)

data = np.array([[1, 2, 3], [1, 2, 3]])

arr = data.view(MyArr)

print(data.max())
print(arr.max())

On numpy 1.13rc1 this prints:

3
[1 2 3]

For the call to arr.max() numpy calls __array_ufunc__, but there doesn't seem to be a way to tell from inside __array_ufunc__ that we should be reducing across the whole array and not just the first dimension. I think this would work properly if numpy were calling __array_ufunc__ with axis=None.

Ping @mhvk

Activity

  1. eric-wieser commented on May 11, 2017

    @eric-wieser
    Member

    Can you print(inp, kwargs) in there too, and give the output?

  2. eric-wieser commented on May 11, 2017

    @eric-wieser
    Member

    Actually, nevermind, I see the issue.

    @mhvk, your normalization in normalize_reduce_args discards all arguments which are None. This is bad for arguments whose default is not None.

    Why do we do this check at all?

  3. ngoldbaum commented on May 11, 2017

    @ngoldbaum
    MemberAuthor

    Similarly for np.any:

    print(np.any(data))
    print(np.any(arr))
    

    prints:

    True
    [ True  True  True]
    

    Here the issue is that numpy is calling np.logical_or.reduce via umr_any.

  4. added this to the 1.13.0 release milestone on May 11, 2017
  5. mhvk commented on May 11, 2017

    @mhvk
    Contributor

    Thanks, that is most clearly a bug! I'll try to get a fix in asap!

  6. mhvk commented on May 11, 2017

    @mhvk
    Contributor

    p.s. The check on None was meant for out -- it is definitely not intended to make this general (it may have something to do with trying to combine all normalizations and then undoing it...)

  7. mhvk commented on May 11, 2017

    @mhvk
    Contributor

    Actually, no, now that I look at it again, I did this on purpose, mistakenly thinking that None was always the default (and wanting to remove any keyword arguments that were at their default). But in fact for axis, 0 is the default. Anyway, I'll correct this to only remove out (also for accumulate, etc.); I should have realized the code sees the arguments early enough that anything there is explicitly passed in.

  8. mhvk commented on May 11, 2017

    @mhvk
    Contributor

    OK, see #9104.

    @ngoldbaum - thanks for reporting -- I guess it is likely you'll find more mistakes, but hopefully not more such blatant ones! @eric-wieser - thanks for identifying the bug so quickly.

  9. charris commented on May 17, 2017

    @charris
    Member

    See #9106.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions