4
$\begingroup$

I am interested in efficient element-wise multiplication of matrices with different dimension. Here is my solution:

Matrix 1 with dim = {3, 4, 4}

mat1 = RandomInteger[10, {3, 4, 4}]
(*{{{6, 0, 0, 3}, {3, 7, 6, 4}, {0, 4, 9, 3}, {6, 9, 3, 0}}, {{1, 7, 1, 
   4}, {3, 7, 6, 2}, {3, 6, 1, 9}, {3, 6, 4, 1}}, {{1, 7, 1, 0}, {4, 
   3, 9, 2}, {9, 10, 1, 3}, {2, 3, 2, 8}}}*)

Matrix 2 (dimension {4, 4}):

mat2 = RandomInteger[10, {4, 4}]
(*{{9, 3, 8, 6}, {2, 0, 2, 5}, {9, 8, 5, 9}, {10, 5, 2, 10}}*)

To let each element in mat2 times with the element in the "subset matrix " of mat1, because the subset has same dimension i.e. {4, 4} in this case, so the element-wise multiplication is legal:

Result = Table[mat2 * mat1 [[i]], {i, 1, 3}]
(*{{{54, 0, 0, 18}, {6, 0, 12, 20}, {0, 32, 45, 27}, {60, 45, 6, 0}}, 
   {{9, 21, 8, 24}, {6, 0, 12, 10}, {27, 48, 5, 81}, {30, 30, 8, 10}},
   {{9, 21, 8, 0}, {8, 0, 18, 10}, {81, 80, 5, 27}, {20, 15, 4, 80}}}*)

but I don't know if there is a better way to do this, especially in terms of achieving better efficiency.

$\endgroup$

2 Answers 2

6
$\begingroup$

You may Compile the code into a listable CompiledFunction as follows:

cf = Compile[{{a, _Integer, 2}, {b, _Integer, 2}},
   a b,
   RuntimeAttributes -> {Listable},
   Parallelization -> True
   ];

Here is a comparison

n = 100000;
m = 16;
mat1 = RandomInteger[10, {n, m, m}];
mat2 = RandomInteger[10, {m, m}];


Result = Table[mat2*mat1[[i]], {i, 1, Length[mat1]}]; // RepeatedTiming // First
Result2 = cf[mat1, mat2]; // RepeatedTiming // First
Result == Result2

0.342

0.067

True

$\endgroup$
4
  • $\begingroup$ Thanks for the powerful answer! $\endgroup$
    – leon365
    Commented Mar 20, 2019 at 23:03
  • 1
    $\begingroup$ You're welcome. $\endgroup$ Commented Mar 20, 2019 at 23:04
  • $\begingroup$ This is genius. mat1 is a rank-three tensor, and this code relies on the rank-2 tensor pattern in the argument of cf binding more strongly than the listability of the arguments, thus splitting mat1 into a list of rank-two tensors but seeing mat2 as a single rank-two tensor (matrix), not a list of rank-one tensors (lists). In this way threading over the list of matrices mat1 works beautifully. $\endgroup$
    – Roman
    Commented Mar 23, 2019 at 6:56
  • $\begingroup$ Yeah. In this sense, CompiledFunctions work slightly differently but IMHO more predictably than conventional function with the attribute Listable. $\endgroup$ Commented Mar 23, 2019 at 7:27
1
$\begingroup$

Using Map:

Result = mat2*# & /@ mat1

This can be parallelized for large systems:

Result = Parallelize[mat2*# & /@ mat1]
$\endgroup$
2
  • 2
    $\begingroup$ Have you really tried and timed the parallelized code? On my machine and with the example from my post, your parallelized code needs about 15 times longer than mat2*# & /@ mat1... $\endgroup$ Commented Mar 22, 2019 at 10:44
  • 1
    $\begingroup$ Yes @HenrikSchumacher I have found the same bizarre result as you. Plus, none of my methods are as fast as yours. $\endgroup$
    – Roman
    Commented Mar 22, 2019 at 10:49

Your Answer

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

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