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
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.
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