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
Add cupy.piecewise
#3329
Add cupy.piecewise
#3329
Conversation
|
Is there a way to support callable functions with kernels ? |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update a document in docs/source/reference
.
@Dahlia-Chehata Could you show us the benchmark script? |
|
@asi1024 Can you please review ? |
cupy/functional/piecewise.py
Outdated
condlist = cupy.asarray(condlist) | ||
condlen = len(condlist) | ||
if diffshape: | ||
if x.ndim == condlist.ndim: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check for x.ndim != condlist.ndim
case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it already checked in this else ?
else:
raise IndexError('boolean index did not match indexed array along '
'dimension 0; dimension is {} but corresponding '
'boolean dimension is {}'
.format(x.shape[0], condlen))
I mean for example the first case will pass and the second will raise the error
x = testing.shaped_arange((2, 3), xp, dtype)
condlist = [False, True]
funclist = [1, 2]
xp.piecewise(x, condlist, funclist)
x = testing.shaped_arange((2, 3), xp, dtype)
condlist = [False, True, True]
funclist = [1, 2]
xp.piecewise(x, condlist, funclist)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why should we check the shape equality only when x.ndim == condlist.ndim
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more question. Why you don't check the shape when diffshape == 0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why should we check the shape equality only when
x.ndim == condlist.ndim
?
I thought I explained it by the above examples. When x.ndim == condlist.ndim
, we should check for the shapes. By not satisfying (x.dim == conlist.ndim) condition, only 2 options are possible now, either condlen == x.shape[0]
(and in this case condlen
should be adjusted to 1 to skip the error in L74 or simply to mean that a special broadcasting will be used for this case) or raise the error because of index mismatch along dimension 0 as it can be seen from the examples I explained here
Does this answer the question ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you check the shape equality only when x.ndim == condlist.ndim
, and don't check when x.ndim != condlist.ndim
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more question. Why you don't check the shape when
diffshape == 0
?
diffshape flag (as by its name) already targets special cases that need a different broadcasting ( list of scalars with multidimensional input or list of tuples/ nested tuples with multidimensional input). Handling these special cases require a pre-step before resuming the normal behavior for all (diffshape == 1, 2 or 0). This extra step can be seen by entering if diffshape:
condition. After that, the default behaviour is applied for different inputs regardless of diffshape value ( that can be seen from line 61, and of course with the exception of transposing condlist in case of diffshape == 1 later on...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you check the shape equality only when
x.ndim == condlist.ndim
, and don't check whenx.ndim != condlist.ndim
?
because I don't need the shapes information when x.ndim != condlist.ndim
Either condlen == x.shape[0] and here special broadcasting is used
x = testing.shaped_arange((2, 3), xp, dtype)
condlist = [False, True]
funclist = [1, 2]
xp.piecewise(x, condlist, funclist)
or raise error because of mismatch along dimension 0
condlist = [False, True, True]
funclist = [1, 2]
xp.piecewise(x, condlist, funclist)
I only care about the shape along dimension 0 when x.ndim != condlist.ndim
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found some different behaviors between this implementation and NumPy's one.
- Only cupy raises
ValueError
.
@testing.for_all_dtypes()
@testing.numpy_cupy_array_equal()
def test_broadcast(self, xp, dtype):
x = testing.shaped_random(shape=(2, 3, 5), xp=xp, dtype=dtype)
condlist = [[[True, False, False], [True, True, True]]]
funclist = [-1, 2]
return xp.piecewise(x, condlist, funclist)
- Only numpy raises error.
@testing.for_all_dtypes()
@testing.numpy_cupy_array_equal()
def test_broadcast(self, xp, dtype):
x = testing.shaped_random(shape=(2, 3, 5), xp=xp, dtype=dtype)
condlist = [[[True, False, False, False, False]], [[True, True, True, True, True]]]
funclist = [-1, 2]
return xp.piecewise(x, condlist, funclist)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look into it
@asi1024 Could you help with travis ? It seems like a common issue |
cupy/functional/piecewise.py
Outdated
if cupy.isscalar(condlist): | ||
condlist = [condlist] | ||
elif isinstance(condlist[0], tuple) and x.ndim != 0: | ||
diffshape = 2 | ||
elif cupy.isscalar(condlist[0]) and x.ndim != 0: | ||
diffshape = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please enhance the coverage of all types of given condlist
. For example, IndexError
will be raised when condlist
is 0-dim ndarray.
cupy/functional/piecewise.py
Outdated
condlist = cupy.asarray(condlist) | ||
condlen = len(condlist) | ||
if diffshape: | ||
if x.ndim == condlist.ndim: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more question. Why you don't check the shape when diffshape == 0
?
Jenkins, test this please. |
Successfully created a job for commit 72035ef: |
Jenkins CI test (for commit 72035ef, target branch master) failed with status FAILURE. |
Jenkins, test this please. |
Successfully created a job for commit 38cd394: |
Jenkins CI test (for commit 38cd394, target branch master) succeeded! |
LGTM. |
No description provided.