
In preparing my email, I was looking for a way to identify a ufunc, other than `isinstance`, since `np.vectorize` and `nb.vectorize` make objects that behave like ufuncs (even obeying NEP 13 semantics, checking for `__array_ufunc__`), but they don't inherit from the `np.ufunc` type. I was thinking that a "ufunc" might be defined as a protocol, like Python's `Sequence` or `Mapping`. I couldn't find a way to do that, particularly because the desired features of a ufunc involve more than having particular methods—they need to check their arguments and call particular methods: `__array_ufunc__`. That's not something one can check with `hasattr`. Sebastian, are you saying that the only definition of "ufunc" is that it inherits from `np.ufunc`? As far as I know, the only way to do that is by implementing it in C (and maybe even depend on a version of the NumPy ABI). But it's useful for libraries other than NumPy to be able to define ufuncs, starting with SciPy, which defines a lot of them. Are there any plans to define "ufunc" as a protocol, rather than a type that must be inherited to be recognized? Its behaviors are well defined at this point. Jim On Thu, Jan 2, 2025, 5:41 AM Sebastian Berg <sebastian@sipsolutions.net> wrote:
Stack is not a generalized ufunc.
It may behave similar to one in many ways, but implementation wise has nothing to do with ufuncs. Also ufuncs do not support an arbitrary number of operands.
`vectorize` can indeed mimic generalized ufuncs, but (unfortunately) doesn't create them as such currently.
- Sebastian
On Tue, 2024-12-31 at 10:20 -0600, Jim Pivarski via NumPy-Discussion wrote:
I think you're right: the function `stack`, as you've defined it, is a gufunc.
Here's an implementation using np.vectorize < https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html> (rather than nb.vectorize <https://numba.readthedocs.io/en/stable/user/vectorize.html>). Since the signature is not "()->()" or "(),()->()" (or similar with a different number of scalar inputs and scalar outputs), it's a generalized ufunc.
def stack(a, b):
... broadcasts = np.broadcast_arrays(a, b)
... return np.stack(broadcasts, axis=-1)
...
stacky = np.vectorize(stack, signature="(),()->(2)")
stacky(np.arange(5), np.arange(5))
array([[0, 0],
[1, 1],
[2, 2],
[3, 3],
[4, 4]])
stacky(np.arange(5), np.array([[1], [2], [3], [4], [5]]))
array([[[0, 1],
[1, 1],
[2, 1],
[3, 1],
[4, 1]],
[[0, 2],
[1, 2],
[2, 2],
[3, 2],
[4, 2]],
[[0, 3],
[1, 3],
[2, 3],
[3, 3],
[4, 3]],
[[0, 4],
[1, 4],
[2, 4],
[3, 4],
[4, 4]],
[[0, 5],
[1, 5],
[2, 5],
[3, 5],
[4, 5]]])
On Tue, Dec 31, 2024 at 2:44 AM john.a.dawson--- via NumPy-Discussion < numpy-discussion@python.org> wrote:
Is the function `stack` above a gufunc? _______________________________________________ NumPy-Discussion mailing list -- numpy-discussion@python.org To unsubscribe send an email to numpy-discussion-leave@python.org https://mail.python.org/mailman3/lists/numpy-discussion.python.org/ Member address: jpivarski@gmail.com
_______________________________________________ NumPy-Discussion mailing list -- numpy-discussion@python.org To unsubscribe send an email to numpy-discussion-leave@python.org https://mail.python.org/mailman3/lists/numpy-discussion.python.org/ Member address: sebastian@sipsolutions.net