Mean tensor product
<p>I have another question which is related to my last problem( <a href="http://stackoverflow.com/questions/40044714/python-tensor-product">Python tensor product</a>). There I found a mistake in my calculation. With np.tensordot I am calculating the following equation:
<a href="https://i.stack.imgur.com/pykbw.png" rel="nofollow"><img src="https://i.stack.imgur.com/pykbw.png" alt="enter image description here"></a>
&lt;..> should display the average.
In python code it does look like this (ewp is a vector and re a tensor): </p>

<pre><code>q1 = numpy.tensordot(re, ewp, axes=(1, 0))
q2 = numpy.tensordot(q1, ewp, axes=(1, 0))
serc = q2 ** 2
</code></pre>

<p>or</p>

<pre><code>serc = numpy.einsum('im, m -&gt; i', numpy.einsum('ilm, l -&gt; im',
numpy.einsum('iklm, k -&gt; ilm', numpy.einsum('ijklm, j -&gt; iklm',
numpy.einsum('ijk, ilm -&gt; ijklm', re, re), ewp), ewp), ewp), ewp)
</code></pre>

<p>Now in both python codes I neglect, that all possibilities are multiplied. But of course <code>w_j</code> and <code>w_k</code> are not independent for <code>j=k</code>. In the case, that only j and k are the same we get <code>&lt; w_j*w_j*w_l*w_m&gt; = &lt;w_j&gt;*&lt;w_l&gt;*&lt;w_m&gt;</code>. For <code>j=k=l</code> we get: <code>&lt; w_j*w_j*w_j*w_m&gt; = &lt;w_j&gt;*&lt;w_m&gt;</code>. For <code>j=k=l=m</code>: <code>&lt; w_j*w_j*w_j*w_j&gt; = &lt;w_j&gt;</code>. Only if all variable are different, independence is true and we get: <code>&lt; w_i*w_j*w_l*w_m&gt; = &lt;w_i&gt;*&lt;w_j&gt;*&lt;w_l&gt;*&lt;w_m&gt;</code>. Now this is what the code does for all possibilities. I hope this makes my problem understandable. Now my question is how can I represent this in my code? </p>

<p>Edit: An idea that I have is to first create a 4dim. tensor which represents <code>&lt;w_j w_k w_l w_m&gt;</code>:</p>

<pre><code>wtensor = numpy.einsum('jkl, m -&gt; jklm', numpy.einsum('jk, l -&gt; jkl',
numpy.einsum('j, k -&gt; jk', ewp, ewp), ewp), ewp)
</code></pre>

<p>Then I need to change the values which are not idependent. I assume they should be on a diagonal? But I really don't know so much about tensor calculus, so at this point I am struggling.
After manipulating the w tensor I would get the result by performing:</p>

<pre><code>serc = numpy.einsum('ijklm, jklm -&gt; i', numpy.einsum('ijk, ilm -&gt;
ijklm', re, re), wtensor)
</code></pre>

<p>Edit2: In another post I asked precisely how I can manipulate the 4dim so that it does fit here. Divakar had a really nice solution which can be seen here: <a href="http://stackoverflow.com/questions/40063034/fill-a-multidimensional-array-efficiently-that-have-many-if-else-statements">Fill a multidimensional array efficiently that have many if else statements</a></p>

<pre><code>from itertools import product

n_dims = 4 # Number of dims
# Create 2D array of all possible combinations of X's as rows
idx = np.sort(np.array(list(product(np.arange(gn),
repeat=n_dims))),axis=1)
# Get all X's indexed values from ewp array
vals = ewp[idx]
# Set the duplicates along each row as 1s. With the np.prod coming up
next,
#these 1s would not affect the result, which is the expected pattern
here.
vals[:,1:][idx[:,1:] == idx[:,:-1]] = 1
# Perform product along each row and reshape into multi-dim array
out = vals.prod(1).reshape([gn]*n_dims)
</code></pre>

<p>The array which I am getting here is <code>wtensor</code> which I now can use in the code above:</p>

<pre><code>serc = numpy.einsum('ijklm, jklm -&gt; i', numpy.einsum('ijk, ilm -&gt;
ijklm', re, re), wtensor)
</code></pre>

<p>This gives me finally the result which I wanted and basically answers the question.
Although there is one problem. The lenght of ewp which then also defines the size of the tensors shouldn't be larger then 6. Otherwise the code will use a lot of memory. My intention was to use it until a size of 8, so that is unfortunately now my next problem. </p>

<p>Well you can do that efficiently with a combination of <code>np.tensordot</code> and <code>np.einsum</code>, like so -</p>

<pre><code>serc = np.einsum('ilm,ilm-&gt;i',re,np.tensordot(re,wtensor,axes=[(1,2),(0,1)]))
</code></pre>

python numpy numpy-einsum