-
Notifications
You must be signed in to change notification settings - Fork 10
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
Multimethods for indexing routines #67
Multimethods for indexing routines #67
Conversation
Here's an implementation for And here's the equivalent of |
|
Some notes regarding the default implementation for
|
Same as for |
For the |
ad1d7a0
to
a30f2d4
Compare
The multimethods added in the last commit: Indexing-like operations
Inserting data into arrays
Iterating over arrays
Some observations:
In [2]: onp.insert([1, 2, 3, 4, 5], [99], -5)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-5f700fb21b7e> in <module>
----> 1 onp.insert([1, 2, 3, 4, 5], [99], -5)
<__array_function__ internals> in insert(*args, **kwargs)
~/miniconda3/envs/unumpy/lib/python3.7/site-packages/numpy/lib/function_base.py in insert(arr, obj, values, axis)
4575 raise IndexError(
4576 "index %i is out of bounds for axis %i with "
-> 4577 "size %i" % (obj, axis, N))
4578 if (index < 0):
4579 index += N
TypeError: %i format: a number is required, not list The error message is not correct. Only problem with unumpy is that some of the defaults that use
Note: Looking into implementing other defaults as well. |
The best path is a good error message.
It shouldn't have a default, it requires mutability of arrays. You're correct on the
Skip it, Dask arrays are immutable. @peterbell10 can you check this PR for CuPy? |
Their behaviour is slightly different. |
(np.fill_diagonal, ([[0, 0], [0, 0]], 1), {}), | ||
(np.nditer, ([[1, 2, 3]],), {}), | ||
(np.ndenumerate, ([[1, 2], [3, 4]],), {}), | ||
(np.ndindex, (3, 2, 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.
This is failing because overridden_class
isn't implemented for the cupy backend.
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 could try implement it but I will not be able to test it. CI does not report the tests in CuPy, right?
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.
You should be able to just copy from the other backends.
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.
Since CI doesn't complain about CuPy I think I will add overriden_class
to it in a separate PR if that's okay with you.
@@ -326,6 +346,16 @@ def test_functions_coerce_with_dtype(backend, method, args, kwargs): | |||
(np.dsplit, ([[[1, 2], [3, 4]], [[5, 6], [7, 8]]], 2), {}), | |||
(np.hsplit, ([[1, 2], [3, 4]], 2), {}), | |||
(np.vsplit, ([[1, 2], [3, 4]], 2), {}), | |||
(np.ix_, ([0, 1], [2, 4]), {}), | |||
(np.unravel_index, ([22, 41, 37], (7, 6)), {}), |
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.
This needs an xfail
. It's broken on cupy's side.
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.
What reason
message do you think it's appropriate?
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.
"cupy.unravel_index is broken in version 6.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.
ix_
is working or broken as well?
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.
ix_
works.
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.
Also, what error is being raised by cupy.unravel_index
(e.g., ValueError
, TypeError
)?
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.
TypeError
.
According to the docs, it's instantiated by
By skipping do you mean adding it to the exceptions list, |
Add it to the exceptions list. |
Adding it to the list still produces the error. Maybe |
It seems most likely a |
Not sure what you mean. |
My bad, it was Line 82 in 8d1ca5c
You need the same approach taken for |
Dask doesn't have Edit: Actually if |
c78da8d
to
e7aa4f9
Compare
unumpy/tests/test_numpy.py
Outdated
if method is np.s_: | ||
assert isinstance(ret, slice) | ||
else: | ||
assert isinstance(ret, onp.ndarray) |
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.
That's interesting, do these return numpy.ndarray
s for other backends as well? If so, that seems to be a bug in the backends.
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.
These classes are not dispatching their arguments and since the backends don't have them (at least Dask and Sparse) unumpy overrides them to NumPy classes which in turn convert the arguments into numpy.ndarray
s. I think that they should dispatch their arguments but either way the NumPy classes will be operating on ndarrays
from other backends (it works in some cases). Other option could be to just return NotImplemented
.
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 debug this, see what's going wrong, but if what you say is correct, NotImplemented
is the way to go.
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.
Maybe create a list of not implemented classes in each backend and inside overridden_class
check if self
is in that list, if yes then return NotImplemented
. I tried dispatching the list-like arguments in __getitem__
. The Dask tests pass because of this behaviour:
In [4]: a = da.from_array(onp.asarray([1, 2, 3]))
In [5]: res = onp.c_[a]
/Users/joaoferreira/miniconda3/envs/unumpy/lib/python3.7/site-packages/dask/array/core.py:1356: FutureWarning: The `numpy.ndim` function is not implemented by Dask array. You may want to use the da.map_blocks function or something similar to silence this warning. Your code may stop working in a future release.
FutureWarning,
In [6]: res
Out[6]:
array([[1],
[2],
[3]])
In [7]: type(res)
Out[7]: numpy.ndarray
And Sparse tests fail because of this:
In [8]: a = sparse.as_coo(onp.asarray([1, 2, 3]))
In [9]: res = onp.c_[a]
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-9-f3f273ef9019> in <module>
----> 1 res = onp.c_[a]
~/miniconda3/envs/unumpy/lib/python3.7/site-packages/numpy/lib/index_tricks.py in __getitem__(self, key)
385 else:
386 item_ndim = ndim(item)
--> 387 newobj = array(item, copy=False, subok=True, ndmin=ndmin)
388 if trans1d != -1 and item_ndim < ndmin:
389 k2 = ndmin - item_ndim
~/miniconda3/envs/unumpy/lib/python3.7/site-packages/sparse/_sparse_array.py in __array__(self, **kwargs)
221 if not AUTO_DENSIFY:
222 raise RuntimeError(
--> 223 "Cannot convert a sparse array to dense automatically. "
224 "To manually densify, use the todense method."
225 )
RuntimeError: Cannot convert a sparse array to dense automatically. To manually densify, use the todense method.
Even if they all passed I'm guessing that we want to avoid calling NumPy's methods/classes with ndarray
s from other backends.
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.
This is fixed by the latest commits. The classes that are not present in a given backend return NotImplemented
.
Note: I had to overwrite _unwrapped
in the call methods because when the backends returned NotImplemented
the classes were defaulting to _unwrapped
at the end of the call stack which made them fail.
I will fast-forward merge |
This should be good to merge now. |
Thanks @joaosferreira! |
This PR intends to expand unumpy's coverage of indexing routines. The multimethods added so far are the following:
Generating index arrays
indices
ix_
ravel_multi_index
unravel_index
diag_indices
diag_indices_from
mask_indices
tril_indices
tril_indices_from
triu_indices
triu_indices_from
Some observations:
ones
creates a COO with afill_value
of 1.0, the call to the next method fails since a zerofill_value
is necessary.ravel_multi_index
andunravel_index
. I'll push them as soon as I have a working prototype but tips on how to implement these are welcomed.c_
,r_
ands_
.Note: I'll be adding more multimethods that target these routines later.