Interface for wrapping random distribution functions (__array_function__, __ufunc__, ?)
![](https://secure.gravatar.com/avatar/eb9e128d8eebbaf4d4d06cd571a05815.jpg?s=120&d=mm&r=g)
Hello there, here is a feature request for the possibility to wrap numpy random distributions to be wrapped by a mechanism like __array_function__ or __array_ufunc__. You can find the GH issue at : https://github.com/numpy/numpy/issues/19382 <https://github.com/numpy/numpy/issues/19382>. This post follows [this one](https://github.com/numpy/numpy/issues/18902 <https://github.com/numpy/numpy/issues/18902>). I figured I should open another issue for `np.random.normal`, but this applies for all distributions I guess. ## Feature Basicaly, I would like that `numpy.random.*` distributions could trigger an interface when passed instances from custom classes, "à la" `__array_ufunc__` or `__array_function__`. Here is an example concept : ```python arr = np.arange(10) # Reference result print(np.mean(arr)) print(np.random.normal(arr)) custom_obj = MyArrayLike(arr) print(np.mean(custom_obj)) # OK : np.mean will trigger __array_function__ interface print(np.random.normal(custom_obj)) # KO : np.random.normal will "only" try to cast the object to float ``` And here is a MWE : ```python import numpy as np np.random.seed(1234) HANDLED_FUNCTIONS = {} class NumericalLabeled(): def __init__(self, value, label=""): self.value = value self.label = label def __repr__(self): return "NumericalLabelled<"+str(self.value) + "," + self.label+">" def __array_function__(self, func, types, args, kwargs): if func not in HANDLED_FUNCTIONS: return NotImplemented return HANDLED_FUNCTIONS[func](*args, **kwargs) def make_numericallabelled(x, label=""): """ Helper function to cast anything into a NumericalLabelled object. """ if isinstance(x, NumericalLabeled): return x else: return NumericalLabeled(x, label=label) # Numpy functions # Override functions - used with __array_function__ def implements(np_function): def decorator(func): HANDLED_FUNCTIONS[np_function] = func return func return decorator @implements(np.random.normal) def np_random_normal(loc=0.0, scale=1.0, **kwargs): # cast both loc and scale into Numericallabelled loc = make_numericallabelled(loc) scale = make_numericallabelled(scale) # check their label is "compatible" if not loc.label == scale.label: raise ValueError return NumericalLabeled(np.random.rand(loc=loc.value, scale=scale.value, **kwargs), loc.label+scale.label) @implements(np.mean) def np_mean(a, *args, **kwargs): return NumericalLabeled(np.mean(a.value, *args, **kwargs), a.label) def main(): # reference result for standard array arr = np.arange(10) print(np.mean(arr)) print(np.random.normal(arr)) # array-like object num_labeled = NumericalLabeled(arr, "toto") print(np.mean(num_labeled)) try: print(np.random.normal(num_labeled)) except Exception as e: print(e) main() ``` which results in ``` 4.5 [ 0.47143516 -0.19097569 3.43270697 2.6873481 3.27941127 5.88716294 6.85958841 6.3634765 8.01569637 6.75731505] NumericalLabelled<4.5,toto> float() argument must be a string or a number, not 'NumericalLabeled' ``` Since the distribution functions accept array as input, I would expect them to be wrappable like many other array functions. ### Versions ``` Python : 3.8.5 (default, Sep 4 2020, 02:22:02) [Clang 10.0.0 ] Numpy : 1.21.0 ``` Cheers
![](https://secure.gravatar.com/avatar/764323a14e554c97ab74177e0bce51d4.jpg?s=120&d=mm&r=g)
On Wed, Jun 30, 2021 at 3:34 PM Yoann Mocquin <mocquin@me.com> wrote:
Hello there,
here is a feature request for the possibility to wrap numpy random distributions to be wrapped by a mechanism like __array_function__ or __array_ufunc__. You can find the GH issue at : https://github.com/numpy/numpy/issues/19382.
This post follows [this one](https://github.com/numpy/numpy/issues/18902). I figured I should open another issue for `np.random.normal`, but this applies for all distributions I guess.
## Feature
Basicaly, I would like that `numpy.random.*` distributions could trigger an interface when passed instances from custom classes, "à la" `__array_ufunc__` or `__array_function__`. Here is an example concept :
The main problem is that these are not functions but methods on a hidden global `RandomState` instance. I haven't kept up fully with all of the efforts in the `__array_*__` proposals, but I do see that methods are explicitly excluded from the `__array_function__` mechanism: https://numpy.org/neps/nep-0018-array-function-protocol.html#non-goals The `RandomState` functionality (and thus all of these aliases in `numpy.random`) are now frozen in functionality (per NEP 19), so we will not be adding this functionality to them. If the `__array_function__` developments eventually work out a good way to wrap methods, then we can think about using that on `Generator`, but I suspect that will not be straightforward. -- Robert Kern
![](https://secure.gravatar.com/avatar/17dd492efaacbd3728c6a4325db77e63.jpg?s=120&d=mm&r=g)
There is an issue that suggests reimplementing many of the Generator methods as ufuncs so they they would inherit all of the free features of ufuncs. It seems like a doable but large project for some useful but nonessential features. Kevin On Wed, Jun 30, 2021, 20:49 Robert Kern <robert.kern@gmail.com> wrote:
On Wed, Jun 30, 2021 at 3:34 PM Yoann Mocquin <mocquin@me.com> wrote:
Hello there,
here is a feature request for the possibility to wrap numpy random distributions to be wrapped by a mechanism like __array_function__ or __array_ufunc__. You can find the GH issue at : https://github.com/numpy/numpy/issues/19382.
This post follows [this one](https://github.com/numpy/numpy/issues/18902). I figured I should open another issue for `np.random.normal`, but this applies for all distributions I guess.
## Feature
Basicaly, I would like that `numpy.random.*` distributions could trigger an interface when passed instances from custom classes, "à la" `__array_ufunc__` or `__array_function__`. Here is an example concept :
The main problem is that these are not functions but methods on a hidden global `RandomState` instance. I haven't kept up fully with all of the efforts in the `__array_*__` proposals, but I do see that methods are explicitly excluded from the `__array_function__` mechanism:
https://numpy.org/neps/nep-0018-array-function-protocol.html#non-goals
The `RandomState` functionality (and thus all of these aliases in `numpy.random`) are now frozen in functionality (per NEP 19), so we will not be adding this functionality to them. If the `__array_function__` developments eventually work out a good way to wrap methods, then we can think about using that on `Generator`, but I suspect that will not be straightforward.
-- Robert Kern _______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@python.org https://mail.python.org/mailman/listinfo/numpy-discussion
participants (3)
-
Kevin Sheppard
-
Robert Kern
-
Yoann Mocquin