2
$\begingroup$

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];
$\endgroup$
3
  • 3
    $\begingroup$ The code you provided executes practically instantaneously and it is reasonably readable. What is the problem with it? $\endgroup$
    – MarcoB
    Feb 17, 2021 at 14:53
  • 3
    $\begingroup$ 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. $\endgroup$
    – kglr
    Feb 17, 2021 at 20:15
  • $\begingroup$ @kglr Thanks, this is faster than my Table. Nice. $\endgroup$
    – xiaohuamao
    Feb 18, 2021 at 0:57

1 Answer 1

3
$\begingroup$

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.)

$\endgroup$
2
  • $\begingroup$ Thank you. Can I include the Total[..., 2] operation into this compiled function? $\endgroup$
    – xiaohuamao
    Feb 18, 2021 at 1:14
  • 4
    $\begingroup$ @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. $\endgroup$
    – Michael E2
    Feb 18, 2021 at 1:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.