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
    Mar 20, 2019 at 23:03
  • 1
    $\begingroup$ You're welcome. $\endgroup$ 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
    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$ 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$ 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
    Mar 22, 2019 at 10:49

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.