The not so slow numpy equivalent is g(x,yT) , using broadcast, followed by f(..., axis=1) .
In [136]: general_inner(np.sum, np.multiply, x, y) Out[136]: array([[ 1.1], [ 3.1]]) In [137]: np.multiply(x,yT) Out[137]: array([[ 0.9, 0.2], [ 2.7, 0.4]]) In [138]: np.sum(np.multiply(x,yT),axis=1) Out[138]: array([ 1.1, 3.1])
similarly for maximum amounts:
In [145]: general_inner(np.max, np.add, x, y) Out[145]: array([[ 2.1], [ 4.1]]) In [146]: np.max(np.add(x,yT), axis=1) Out[146]: array([ 2.1, 4.1])
There is a potential confusion that np.add , np.multiply , np.maximum are ufunc , and np.sum , np.prod , np.max are not, but accept the axis and keepdims . (edit: np.add.reduce is the equivalent of ufunc np.sum .)
In [152]: np.max(np.add(x,yT), axis=1, keepdims=True) Out[152]: array([[ 2.1], [ 4.1]])
There was an old improvement request for implementing this kind of thing at np.einsum . This implements sum of products calculation with a high degree of index control. Thus, conceptually, he could perform max of sums with the same indexing control. But as far as I know, no one tried to implement it.
This generic internal product was a nice feature of APL (it was my main language decades ago). But, apparently, it is not so useful that he migrated from this family of languages. MATLAB has nothing of the kind.
Is there anything APL and J can do with this construct that cannot be done in numpy with the kind of broadcast we demonstrated?
With more general forms of x and y I need to add newaxis as indicated in another answer
In [176]: x = np.arange(3*4).reshape(4,3) In [177]: y = np.arange(3*2).reshape(3,2) In [178]: np.sum(np.multiply(x[...,None],y[None,...]),axis=1) Out[178]: array([[10, 13], [28, 40], [46, 67], [64, 94]]) In [179]: np.max(np.add(x[...,None],y[None,...]),axis=1) Out[179]: array([[ 6, 7], [ 9, 10], [12, 13], [15, 16]])
generalizing to 3d, using the idea of matmul last dull / second last from matmul :
In [195]: x = np.arange(2*4*5).reshape(2,4,5) In [196]: y = np.arange(2*5*3).reshape(2,5,3) In [197]: np.einsum('ijk,ikm->ijm', x, y).shape Out[197]: (2, 4, 3) In [203]: np.add.reduce(np.multiply(x[...,None], y[...,None,:,:]), axis=-2).shape Out[203]: (2, 4, 3) # shapes broadcast: (2,4,5,n) * (2,n,5,3) => (2,4,5,3); sum on the 5
Thus, although numpy (and MATLAB) does not have a special syntax, such as APL , the idea of an extension operation (outter) followed by a reduction is quite common.
testing other ufunc :
In [205]: np.maximum.reduce(np.add(x[...,None], y[...,None,:,:]), axis=-2).shape Out[205]: (2, 4, 3) In [208]: np.logical_or.reduce(np.greater(x[...,None], y[...,None,:,:]), axis=-2).shape Out[208]: (2, 4, 3)