I need to compute a double sum over a weighted matrix product: $L[M]=\sum_{i,j}^{N}\Lambda[[i]]\;\omega[[i]].M.\omega^{\dagger}[[j]]$.
$\Lambda$ is a list of with N complex values(weights) and $\omega$ is a list of N matrices, so that each different $i$ corresponds to different a matrix. I need to compute this function many times with different M matrices, so I need to optimise the execution time considerably. The final result i am after is a matrix with the elements
$\mathcal{L}_{j,l}=Tr[ M_{j}^{}\dagger]L[M_{l}]]$
The matrix $\mathcal{L}$ is large ($80^2\times 80^2$), and I have parallelised my code over $j$ and $l$, so I cannot parallelise the $L$ function. As I need to compute the value of $L[M_{i}]$ 6400 I really need a fast way to compute it. One thing which I hoped could speed things up is the fact that $M$ matrices are zero matrices with only one element different from 0, which is then 1. I have not succeeded in coding this an efficient way in mathematica as the following takes 2.5s to run on my current machine.
n = 90;
Λ = RandomReal[1, n];
ω = Table[RandomReal[1, {80, 80}], {i, 1, n}];
M = IdentityMatrix[80^2];
M1 = Partition[M[[All, 1]], 80];
M2 = Partition[M[[All, 2]], 80];
LM[M_] := Sum[Λ[[i]] ω[[i]].M.ConjugateTranspose[ω[[j]]], {i, 1, n}, {j, 1, n}]
AbsoluteTiming[LM[M1];]
Edit
As suggested by J.M. I have tried to "vectorise" the sum. In theory I think this should work: $A=(c_1 \omega_1.M\quad c_2\omega_2.M\quad c_3\omega_3.M\quad...)$
$B=\begin{bmatrix}\omega_1 &\omega_2&\omega_3&...\\ \omega_1 &\omega_2&\omega_3&...\\ \omega_1 &\omega_2&\omega_3&...\\ .&.&.&.\\ .&.&.&.\\ \end{bmatrix}$
$L=Total[A.B]$
But doing this the obvious way in mathematica gives me a wrong result. My implementation looks like this:
(*simple test arrays*)
w = {{{1, 2}, {3, 1}}, {{1, 1}, {1, 2}}};
c = {2, 3};
M = {{1, 0}, {0, 0}};
(*Correct results*)
Correct = Sum[c[[i]] w[[i]].M.w[[j]], {i, 1, Length[c]}, {j, 1, 2}]//MatrixForm
(*Vectorisation of double sum*)
A = Table[c[[i]] w[[i]].M, {i, 1, Length[c]}];
B = Table[w[[i]], {j, 1, 2}, {i, 1, Length[c]}];
VecRes = Total[A.B]
'VecRes' is a completely different format ({2,2,2,2}) than the expected output which should be a $2\times 2$ matrix and not an array of matrices. As Michael points out this is due to the indexing being wrong, so flatten could be used to fix.
Vectorisation Remarks
Huge thanks to Michael for the thorough description! Having incorporated Michael Weyrauch example for my entire problem have really shown the power of the vectorisation. What previously took 2400s with 4 cpu now take a single cpu 10s! The only drawback is that I do not know how to effectively parallelise this algorithm compared to the previous sum which was embarrassingly parallel. However Michaels algorithm is still much quicker, but if it can be parallelised efficiently it would be a really nice!
Memory effects
This procedure seems to take up a huge amount of memory. So much in fact that it easily uses all of the 65gb available on 16 core machine and thereby shutting it down. Any clever way of avoiding this? An example of a line that uses all the memory:
Lx1 = Total[Flatten[(La*om).M.
Conjugate[Flatten[om, {{3}, {1}, {2}}]], {{1}, {4}, {3}, {2}, {5}}], 2];
Where the dimensions are: Dim[La]={1561}, Dim[om]={1561,80,80}, Dim[M]={80,6400,80}.
So La is a list of complex numbers, om is a tensor with 1561 different 80x80 matrices, and similar for M except it consists of 6400 matrices.
Dot[]
product? $\endgroup$