<p dir="ltr">Hi Travis,</p>
<p dir="ltr">On Mar 16, 2016 9:52 AM, "Travis Oliphant" <<a href="mailto:travis@continuum.io">travis@continuum.io</a>> wrote:<br>
><br>
> Hi everyone,<br>
><br>
> Can you help me understand why the stricter changes to generalized ufunc argument checking no now longer allows scalars to be interpreted as 1-d arrays in the core-dimensions? <br>
><br>
> Is there a way to specify in the core-signature that scalars should be allowed and interpreted in those cases as an array with all the elements the same?   This seems like an important feature. </p>
<p dir="ltr">Can you share some example of when this is useful?</p>
<p dir="ltr">The reasoning for the change was that broadcasting is really about aligning a set of core elements for parallel looping, and in the gufunc case with arbitrary core kernels that might or might not have any simple loop structure inside them, it's not at all obvious that it makes sense. (Of course we still use broadcasting to line up different instances of the core elements themselves, just not to manufacture the internal shape of the core elements.) In fact there are examples where it clearly doesn't make sense, I don't think we were able to come up with any compelling examples where it did make sense (which is one reason why I'm interested to hear what yours is :-)), and there's not a single obvious way to reconcile broadcasting rules and gufunc's named axis matching, so, when in doubt refuse the temptation to guess.</p>
<p dir="ltr">(Example of when it doesn't make sense: matrix_multiply with (n,k),(k,m)->(n,m) used to produce all kinds of different counterintuitive behaviors if one or both of the inputs were scalar or 1d. In this case making it an error is a clear improvement IMHO. And for something like inv that takes a single input with signature (n,n), if you get (1,n) do you broadcast that to (n,n)? If not, why not? For regular broadcasting the question makes no sense but once you have named axis matching then suddenly it's not obvious.)</p>
<p dir="ltr">> Here's an example: <br>
><br>
> myfunc with core-signature (t),(k),(k) -> (t)<br>
><br>
> called with myfunc(arr1, arr2, scalar2).<br>
><br>
> This used to work in 1.9 and before and scalar2 was interpreted as a 1-d array the same size as arr2.   It no longer works with 1.10.0 but I don't see why that is an improvement.  <br>
><br>
> Thoughts?   Is there a work-around that doesn't involve creating a 1-d array the same size as arr2 and filling it with scalar2?</p>
<p dir="ltr">A better workaround would be to use one of the np.broadcast* functions to request exactly the broadcasting you want and make an arr2-sized view of the scalar. In this case where you presumably (?) want to allow the last two arguments to be broadcast against each other arbitrarily:</p>
<p dir="ltr">arr2, arr3 = np.broadcast_arrays(arr2, scalar)<br>
myufunc(arr1, arr2, arr3)</p>
<p dir="ltr">A little wordier than implicit broadcasting, but not as bad as manually creating an array, and like implicit broadcasting the memory overhead is O(1) instead of O(size).</p>
<p dir="ltr">-n</p>