IntelPython / dpctl

Python SYCL bindings and SYCL-based Python Array API library
https://intelpython.github.io/dpctl/
Apache License 2.0
97 stars 29 forks source link

Question about behavior with no array passed to `dpt.broadcast_arrays` #1718

Closed antonwolfy closed 5 days ago

antonwolfy commented 6 days ago

The below example works differently with numpy and numpy.array_api:

import numpy, dpctl, dpctl.tensor as dpt
import numpy.array_api as na

numpy.broadcast_arrays()
# Out: []

na.broadcast_arrays()
# Out: []

numpy.__version__
# Out: '1.26.4'

dpt.broadcast_arrays()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[9], line 1
----> 1 dpt.broadcast_arrays()

File ~/miniforge3/envs/dpnp_dev/lib/python3.11/site-packages/dpctl/tensor/_manipulation_functions.py:272, in broadcast_arrays(*args)
    269     if not isinstance(X, dpt.usm_ndarray):
    270         raise TypeError(f"Expected usm_ndarray type, got {type(X)}.")
--> 272 shape = _broadcast_shapes(*args)
    274 if all(X.shape == shape for X in args):
    275     return args

File ~/miniforge3/envs/dpnp_dev/lib/python3.11/site-packages/dpctl/tensor/_manipulation_functions.py:83, in _broadcast_shapes(*args)
     78 """
     79 Broadcast the input shapes into a single shape;
     80 returns tuple broadcasted shape.
     81 """
     82 array_shapes = [array.shape for array in args]
---> 83 return _broadcast_shape_impl(array_shapes)

File ~/miniforge3/envs/dpnp_dev/lib/python3.11/site-packages/dpctl/tensor/_manipulation_functions.py:43, in _broadcast_shape_impl(shapes)
     41 mutable_shapes = False
     42 nds = [len(s) for s in shapes]
---> 43 biggest = max(nds)
     44 sh_len = len(shapes)
     45 for i in range(sh_len):

ValueError: max() arg is an empty sequence

dpctl.__version__
# Out: '0.18.0dev0+77.g26d34f565d'

From the Python array API it doesn't look clear enough if empty list should be supported and the empty list to be returned.

In any case that corner case needs to be properly handled by dpctl, because the raised exception ValueError: max() arg is an empty sequence doesn't sound clear about the reason of failure.

ndgrigorian commented 6 days ago

Spec is definitely unclear about expected behavior, however

Broadcasts one or more arrays against one another.

leads me to believe that it is intended to be a minimum of 1 array.

Still, as pointed out, that exception is entirely unhelpful.