Week-9 Ufunc Overrides

This week I'm still working on the pull request for ufunc overrides, however I think it is finally nearing completion. The implementation is working as described and all tests are passing. I'm looking forward to working on SciPy again.

The main aspects I've been working on are ufunc overrides method resolution order, and argument normalization.

Method Resolution Order (MRO)

Python functions in certain cases have a special MRO which is a bit more complicated than the default left to right. Whenever ther right argument is a subtype of the left argument its special method corresponding to the calling function is called first. So for example, add(a, b) would normally call a.__add__(b) but if b is a subtype of a, then b.__radd__(a) is called. However there are no examples in the Python standard library of a ternary or greater function from which we can copy. So we have tried to generalize this concept to a higher order.

The MRO algorithm is succinctly stated by @njsmith as:

While there remain untried inputs, pick the leftmost one which does not have a proper subtype still remaining to be checked.

Where inputs are the inputs to the ufunc. Trying an input refers to calling its __numpy_ufunc__ method (if it has one) and seeing that it does not return NotImplemented.

So Basically if a ufunc has three inputs (a, b, as) in that order, where as is a subtype of a. They will be tried in the order b > as > a.

Argument Normalization

Many of NumPy's ufuncs can take a out argument, which specifies where the output of the ufunc is assigned. The out argument can be passed as either a positional, or keyword argument. So naïvely checking a ufuncs arguments for __numpy_ufunc__ and then passing said arguments unaltered is not always sensible. So given nargs - the number of args, and nin - the number of inputs, we can check for an out positional argument and move it to the keyword arguments. The normalized arguments are then passed the __numpy_ufunc__ method.


Comments powered by Disqus