# Multiply lists: element-wise but matrix-like in the last 2 levels

How can I do the following computation more efficiently? We have nested lists and want to multiply element-wise, where the 'element' is the deepest 2 levels treated like normal matrix multiplication. And then we Total all but the last 2 levels. In reality I need to deal with larger size (like d1=300 but still small d2) lists many many times. Probably the following is not the optimal way to program it.

d1 = 10; d2 = 2;
mat1 = RandomComplex[1 + I, {d1, d1, d2, d2}];
mat2 = RandomComplex[1 + I, {d1, d1, d2, d2}];
mat3 = ConjugateTranspose[mat1];
data = Table[mat1[[i, j]] . mat2[[i, j]] . mat3[[i, j]], {i, d1}, {j, d1}];
Total[data, 2];

• The code you provided executes practically instantaneously and it is reasonably readable. What is the problem with it? – MarcoB Feb 17 at 14:53
• I also like your method. You can also do Apply[Dot, Transpose[{mat1, mat2, mat3}, {3, 1, 2}], {2}] to get data but it is easier to see what is being done using your approach. – kglr Feb 17 at 20:15
• @kglr Thanks, this is faster than my Table. Nice. – xiaohuamao Feb 18 at 0:57

If the numbers are machine floats (complex ones), this will be fast:

data3 = Compile[
{{m1, _Complex, 2}, {m2, _Complex, 2}, {m3, _Complex, 2}},
m1 . m2 . m3,
RuntimeAttributes -> {Listable},
Parallelization -> True][mat1, mat2, mat3];


(If d1 is changed to d1 =300, then the OP's Table[] runs in 0.34 sec. and the above in 0.012 sec.)

• Thank you. Can I include the Total[..., 2] operation into this compiled function? – xiaohuamao Feb 18 at 1:14
• @xiaohuamao Apparently not: the Total[a, 2] form is not compilable. However, you can put it outside: Total[Compile[ ...][mat1, mat2, mat3], 2]. Total is quite efficient on packed arrays (which is what Compile returns), and putting it inside Compile doesn't usually speed it up much. In this case adding it on the outside adds very little time for d1 = 300. – Michael E2 Feb 18 at 1:23