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] Ufuncs box scalars in array #946

Open
suranap opened this issue May 6, 2024 · 3 comments
Open

[BUG] Ufuncs box scalars in array #946

suranap opened this issue May 6, 2024 · 3 comments

Comments

@suranap
Copy link

suranap commented May 6, 2024

Software versions

Python : 3.10.13 | packaged by conda-forge | (main, Dec 23 2023, 15:36:39) [GCC 12.3.0]
Platform : Linux-5.4.0-169-generic-x86_64-with-glibc2.31
Legion : v23.11.00.dev-54-g40f6061
Legate : 23.11.00.dev+54.g40f6061
Cunumeric : 23.11.00.dev+36.gb2912ed7
Numpy : 1.26.4
Scipy : 1.12.0
Numba : 0.59.0
CTK package : cuda-version-11.7-h67201e3_2 (conda-forge)
GPU driver : 535.54.03
GPU devices :
GPU 0: Tesla P100-SXM2-16GB
GPU 1: Tesla P100-SXM2-16GB
GPU 2: Tesla P100-SXM2-16GB
GPU 3: Tesla P100-SXM2-16GB

Jupyter notebook / Jupyter Lab version

No response

Expected behavior

Expect cunumeric to return a scalar value just like numpy.

Welcome to Legion Python interactive console
>>> import cunumeric as cnp
>>> import numpy as np
>>> np.sqrt(4.0)
2.0
>>> cnp.sqrt(4.0)
array(2.)

Observed behavior

Looks like ufuncs applied to a scalar returns an array.

>>> cnp.add(1,2)
array(3)
>>> cnp.power(3,2)
array(9)
>>> cnp.power(3.0,2.0)
array(9.)
>>> cnp.tan(4.0)
array(1.15782128)
>>> cnp.equal(1, 1)
array(True)
>>>

Example code or instructions

see above

Stack traceback or browser console output

No response

@manopapad
Copy link
Contributor

Is there a need to match this behavior?

NumPy will often (but not always) convert a 0d array result to a python-level scalar, but cuNumeric avoids doing that, because in cuNumeric an array value can potentially represent an asynchronous computation. Passing that value in its unevaluated form to another operation normally doesn't force the program to block, which we prefer. Converting to a python-level scalar forces blocking, so we don't do it eagerly.

So the general policy (which is, admittedly, not well-documented currently) is that we don't guarantee that operations which in NumPy return scalars always return scalars in cuNumeric. But the values that we do return should always be usable in place of a scalar. For example, if the user tries to do anything with the result of cn.random.randint(1234, size=None) that requires the value right away, e.g. printing it out, then we block and wait for the computation to complete.

@lightsighter
Copy link
Contributor

So the general policy (which is, admittedly, not well-documented currently) is that we don't guarantee that operations which in NumPy return scalars always return scalars in cuNumeric. But the values that we do return should always be usable in place of a scalar.

I'll also note that is consistent with Python's duck typing philosophy. Types of objects do not need to match, they just need to behave identically. In this case, returning something that behaves like a scalar enables more asynchronous execution and better performance.

@suranap
Copy link
Author

suranap commented May 10, 2024

I ported Autograd on top of cuNumeric to do differential programming. This means there's yet another wrapper layer pretending to be NumPy. I got the following error: *** ValueError: Out-of-bounds projection on dimension 0 with index 1 for a store of shape Shape((1, 194, 3072)) and tracked it to this issue.

I'll debug further to see where this distinction between scalar and 0d array is popping up.

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

No branches or pull requests

3 participants