[Numpy-discussion] Proposed new feature for numpy.einsum: repeated output subscripts as diagonal
Sebastian Berg
sebastian at sipsolutions.net
Fri Aug 15 09:53:23 EDT 2014
On Do, 2014-08-14 at 12:42 -0700, Stephan Hoyer wrote:
> I think this would be very nice addition.
>
>
> On Thu, Aug 14, 2014 at 12:21 PM, Benjamin Root <ben.root at ou.edu>
> wrote:
> You had me at Kronecker delta... :-) +1
>
Sounds good to me. I don't see a reason for not relaxing the
restriction, unless there is some technical issue, but I doubt that.
- Sebastian
>
>
> On Thu, Aug 14, 2014 at 3:07 PM, Pierre-Andre Noel
> <noel.pierre.andre at gmail.com> wrote:
> (I created issue 4965 earlier today on this topic, and
> I have been
> advised to email to this mailing list to discuss
> whether it is a good
> idea or not. I include my original post as-is,
> followed by additional
> comments.)
>
> I think that the following new feature would make
> `numpy.einsum` even
> more powerful/useful/awesome than it already is.
> Moreover, the change
> should not interfere with existing code, it would
> preserve the
> "minimalistic" spirit of `numpy.einsum`, and the new
> functionality would
> integrate in a seamless/intuitive manner for the
> users.
>
> In short, the new feature would allow for repeated
> subscripts to appear
> in the "output" part of the `subscripts` parameter
> (i.e., on the
> right-hand side of `->`). The corresponding dimensions
> in the resulting
> `ndarray` would only be filled along their diagonal,
> leaving the off
> diagonal entries to the default value for this `dtype`
> (typically zero).
> Note that the current behavior is to raise an
> exception when repeated
> output subscripts are being used.
>
> This is simplest to describe with an example involving
> the dual behavior
> of `numpy.diag`.
>
> ```python
> # Extracting the diagonal of a 2-D array.
> A = arange(16).reshape(4,4)
> print(diag(A)) # Output: [ 0 5 10 15 ]
> print(einsum('ii->i', A)) # Same as previous line
> (current behavior).
>
> # Constructing a diagonal 2-D array.
> v = arange(4)
> print(diag(v)) # Output: [[0 0 0 0] [0 1 0 0] [0 0 2
> 0] [0 0 0 3]]
> print(einsum('i->ii', v)) # New behavior would be same
> as previous line.
> # The current behavior of the previous line is to
> raise an exception.
> ```
>
> By opposition to `numpy.diag`, the approach
> generalizes to higher
> dimensions: `einsum('iii->i', A)` extracts the
> diagonal of a 3-D array,
> and `einsum('i->iii', v)` would build a diagonal 3-D
> array.
>
> The proposed behavior really starts to shine in more
> intricate cases.
>
> ```python
> # Dummy values, these should be probabilities to make
> sense below.
> P_w_ab = arange(24).reshape(3,2,4)
> P_y_wxab = arange(144).reshape(3,3,2,2,4)
>
> # With the proposed behavior, the following two lines
> should be equivalent.
> P_xyz_ab = einsum('wab,xa,ywxab,zy->xyzab', P_w_ab,
> eye(2), P_y_wxab,
> eye(3))
> also_P_xyz_ab = einsum('wab,ywaab->ayyab', P_w_ab,
> P_y_wxab)
> ```
>
> If this is not convincing enough, replace `eye(2)` by
> `eye(P_w_ab.shape[1])` and replace `eye(3)` by
> `eye(P_y_wxab.shape[0])`,
> then imagine more dimensions and repeated indices...
> The new notation
> would allow for crisper codes and reduce the
> opportunities for dumb
> mistakes.
>
> For those who wonder, the above computation amounts to
> $P(X=x,Y=y,Z=z|A=a,B=b) = \sum_w P(W=w|A=a,B=b) P(X=x|
> A=a)
> P(Y=y|W=w,X=x,A=a,B=b) P(Z=z|Y=y)$ with $P(X=x|A=a)=
> \delta_{xa}$ and
> $P(Z=z|Y=y)=\delta_{zy}$ (using LaTeX notation, and
> $\delta_{ij}$ is
> [Kronecker's
> delta](http://en.wikipedia.org/wiki/Kronecker_delta)).
>
> (End of original post.)
>
> I have been told by @jaimefrio that "The best way of
> getting a new
> feature into numpy is putting it in yourself." Hence,
> if discussions
> here do reveal that this is a good idea, then I may
> give a try at coding
> it myself. However, I currently know nothing of the
> inner workings of
> numpy/ndarray/einsum, and I have higher priorities
> right now. This means
> that it could take a long while before I contribute
> any code, if I ever
> do. Hence, if anyone feels like doing it, feel free to
> do so!
>
> Also, I am aware that storing a lot of zeros in an
> `ndarray` may not, a
> priori, be a desirable avenue. However, there are
> times where you have
> to do it: think of `numpy.eye` as an example. In my
> case of application,
> I use such diagonal structures in the initialization
> of an `ndarray`
> which is later updated through an iterative process.
> After these
> iterations, most of the zeros will be gone. Do other
> people see a use
> for such capabilities?
>
> Thank you for your time and have a nice day.
>
> Sincerely,
>
> Pierre-André Noël
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
>
>
>
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
>
>
>
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
More information about the NumPy-Discussion
mailing list