You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What is the best way to test broadcasting? The simplest would be to use a function like numpy.broadcast_arrays or numpy.broadcast_to, but these aren't listed in the spec. And even NumPy doesn't have a function that directly implements the shape broadcasting algorithm—it can only be done to explicit arrays. The spec says broadcasting should apply to all elementwise operations. What is a good elementwise operation that we can use to test only the broadcasting semantics? Or should we make sure to test all of them?
The spec doesn't actually specify how resulting broadcast array should look, only what its shape is. Is this intentional? Should we test this? If not, it means we don't actually test the result of a broadcasted operation, only that the shape/errors are correct.
As I understand it, "potentially enable more memory-efficient element-wise operations" means that broadcasting does not necessarily need to be done in a memory-efficient way, i.e., libraries are free to copy axes across broadcast dimensions rather than using something like a stride trick.
What is the best way to test broadcasting? The simplest would be to use a function like numpy.broadcast_arrays or numpy.broadcast_to, but these aren't listed in the spec.
I think broadcasting is a behaviour that needs testing for every function that has broadcast-able inputs, so it's a big job. For now I'd take the one or a handful of functions you'll start with, and see if you can write a broadcast test with shape logic that can be reused.
And even NumPy doesn't have a function that directly implements the shape broadcasting algorithm
Yes this is a pain, we really should have such a function in NumPy. I think we need it here. The algorithm isn't actually all that hard - I suspect there's an implementation in pure Python floating around somewhere.
it can only be done to explicit arrays. The spec says broadcasting should apply to all elementwise operations. What is a good elementwise operation that we can use to test only the broadcasting semantics? Or should we make sure to test all of them?
add?
The spec doesn't actually specify how resulting broadcast array should look, only what its shape is. Is this intentional? Should we test this? If not, it means we don't actually test the result of a broadcasted operation, only that the shape/errors are correct.
Ah. I had to read that section again, you're right - it's missing a statement on how values in the array being broadcasted are "virtually duplicated" (not sure that's great wording).
As I understand it, "potentially enable more memory-efficient element-wise operations" means that broadcasting does not necessarily need to be done in a memory-efficient way, i.e., libraries are free to copy axes across broadcast dimensions rather than using something like a stride trick.
Indeed. Strides are explicitly out of scope - there are arrays that do not have a strided implementation (e.g. JAX, Dask). That's an implementation detail, and the spec attempts to be careful not to specify anything that puts unnecessary constraints on any library - JIT compilers, lazy evaluation, distributed arrays, GPU arrays, etc. all should be possible.
Re: what an array looks like. That is covered, perhaps too obliquely, here:
Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension.
The key phrase being "virtually repeated".
May be worthwhile for me to add an example to the spec doc to show what the broadcasting algorithm means in practice.
Yes this is a pain, we really should have such a function in NumPy. I think we need it here. The algorithm isn't actually all that hard - I suspect there's an implementation in pure Python floating around somewhere.
I was actually going to open an issue on NumPy about this some time ago, but never got around to it. I've done so here numpy/numpy#17217.
I believe there is a bug in the broadcasting pseudocode. If I implement it directly, I get IndexErrors from the test cases. I believe the correct code should be
i. If N1-N+i >= 0, let d1 be the size of dimension N1 - N + i for array A (i.e., the result of shape1[N1 - N + i]); else, let d1 be 1.
ii. If N2-N+i >= 0, let d2 be the size of dimension N2 - N + i for array B (i.e., the result of shape2[N2 - N + i]); else, let d2 be 1.
(also note that the spec says n on these lines when I believe it means to say i)
Here is the function as defined in the spec
classBroadcastError(Exception):
passdefbroadcast_shapes(shape1, shape2):
""" Broadcast shapes `shape1` and `shape2`. The code in this function should follow the pseudocode in the spec as closely as possible. """N1=len(shape1)
N2=len(shape2)
N=max(N1, N2)
shape= [None]*Ni=N-1whilei>=0:
ifN1-N+i>=0:
d1=shape1[i]
else:
d1=1ifN2-N+i>=0:
d2=shape2[i]
else:
d2=1ifd1==1:
shape[i] =d2elifd2==1:
shape[i] =d1elifd1==d2:
shape[i] =d1else:
raiseBroadcastErrori=i-1returntuple(shape)
And here is what I believe is the correct version
classBroadcastError(Exception):
passdefbroadcast_shapes(shape1, shape2):
""" Broadcast shapes `shape1` and `shape2`. The code in this function should follow the pseudocode in the spec as closely as possible. """N1=len(shape1)
N2=len(shape2)
N=max(N1, N2)
shape= [None]*Ni=N-1whilei>=0:
ifN1-N+i>=0:
d1=shape1[N1-N+i] # This line is differentelse:
d1=1ifN2-N+i>=0:
d2=shape2[N2-N+i] # This line is differentelse:
d2=1ifd1==1:
shape[i] =d2elifd2==1:
shape[i] =d1elifd1==d2:
shape[i] =d1else:
raiseBroadcastErrori=i-1returntuple(shape)
We have tests for broadcasting but they only cover the elementwise functions. We need to extend it to operators (including the in-place operator logic), as well as other functions. c.f. #24
We have tests for broadcasting but they only cover the elementwise functions. We need to extend it to operators (including the in-place operator logic), as well as other functions. c.f. #24
Activity
rgommers commentedon Aug 28, 2020
See my answer on gh-2.
I think broadcasting is a behaviour that needs testing for every function that has broadcast-able inputs, so it's a big job. For now I'd take the one or a handful of functions you'll start with, and see if you can write a broadcast test with shape logic that can be reused.
Yes this is a pain, we really should have such a function in NumPy. I think we need it here. The algorithm isn't actually all that hard - I suspect there's an implementation in pure Python floating around somewhere.
add?Ah. I had to read that section again, you're right - it's missing a statement on how values in the array being broadcasted are "virtually duplicated" (not sure that's great wording).
Indeed. Strides are explicitly out of scope - there are arrays that do not have a strided implementation (e.g. JAX, Dask). That's an implementation detail, and the spec attempts to be careful not to specify anything that puts unnecessary constraints on any library - JIT compilers, lazy evaluation, distributed arrays, GPU arrays, etc. all should be possible.
kgryte commentedon Aug 29, 2020
Re: what an array looks like. That is covered, perhaps too obliquely, here:
The key phrase being "virtually repeated".
May be worthwhile for me to add an example to the spec doc to show what the broadcasting algorithm means in practice.
asmeurer commentedon Sep 1, 2020
I was actually going to open an issue on NumPy about this some time ago, but never got around to it. I've done so here numpy/numpy#17217.
asmeurer commentedon Sep 1, 2020
I believe there is a bug in the broadcasting pseudocode. If I implement it directly, I get IndexErrors from the test cases. I believe the correct code should be
(also note that the spec says
non these lines when I believe it means to sayi)Here is the function as defined in the spec
And here is what I believe is the correct version
And here are the test cases from the spec
kgryte commentedon Sep 1, 2020
@asmeurer Thanks for catching this. Will submit a patch to the spec shortly.
Correct broadcast_shapes algorithm
kgryte commentedon Sep 2, 2020
@asmeurer Patch submitted: data-apis/array-api#30.
asmeurer commentedon Oct 4, 2021
We have tests for broadcasting but they only cover the elementwise functions. We need to extend it to operators (including the in-place operator logic), as well as other functions. c.f. #24
honno commentedon Dec 22, 2021
Fixed in #35.
The suite now tests broadcasting for all relevant functions in the current spec, so closing.