# [Numpy-discussion] Bringing order to higher dimensional operations

Sebastian Berg sebastian at sipsolutions.net
Fri Jul 19 12:05:00 EDT 2013

```On Fri, 2013-07-19 at 16:31 +0100, Nathaniel Smith wrote:
> On Thu, Jul 18, 2013 at 2:23 PM, Sebastian Berg
> <sebastian at sipsolutions.net> wrote:
> > It is so difficult because of the fact that dot is basically a
> > combination of many functions:
> >   o vector * vector -> vector
> >   o vector * matrix -> matrix (add dimensions to vector on right)
> >   o matrix * vector -> matrix (add dimensions to vector on left)
> >   o matrix * matrix -> matrix
> > plus scalar cases.
>
> Though, just throwing this out there for the archives since I was
>
> I think we *could* consolidate all dot's functionality into a single
> gufunc, with a few small changes:
>
> 1) Deprecate and get rid of the scalar special cases. (For those
> following along: right now, np.dot(10, array) does scalar
> multiplication, but this doesn't make much sense conceptually, it's
> not documented, and I don't think anyone uses it. Except maybe
> np.matrix.__mul__, but that could be fixed.)
>
> 2) Deprecate the strange "broadcasting" behaviour for high-dimensional
> inputs, in favor of the gufunc version suggested in the previous
> email.
>
> That leaves the vector * vector, vector * matrix, matrix * vector,
> matrix * matrix cases. To handle these:
>
> 3) Extend the gufunc machinery to understand the idea that some core
> dimensions are allowed to take on a special "nonexistent" size. So the
> signature for dot would be:
>   (m*,k) x (k, n*) -> (m*, n*)
> where '*' denotes dimensions who are allowed to take on the
> "nonexistent" size if necessary. So dot(ones((2, 3)), ones((3, 4)))
> would have
>   m = 2
>   k = 3
>   n = 4
> and produce an output with shape (m, n) = (2, 4). But dot(ones((2,
> 3)), ones((3,))) would have
>   m = 2
>   k = 3
>   n = <nothing>
> and produce an output with shape (m, n) = (2, <nothing>) = (2,). And
> dot(ones((3,)), ones((3,))) would have
>   m = <nothing>
>   k = 3
>   n = <nothing>
> and produce an output with shape (m, n) = (<nothing>, <nothing>) = (),
> i.e., dot(vector, vector) would return a scalar.
>
> I'm not sure if there are any other cases where this would be useful,
> but even if it were just for 'dot', that's still a pretty important
> case that might justify the mechanism all on its own.
>

Yeah this would work. It is basically what np.linalg.solve currently
does in the preparation step. So maybe this is not that bad implemented
in the machinery. The logic itself is pretty simple after all. Though it
would be one of those features I would probably not want to see used a
lot ;).

- Sebastian

> -n
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
>

```