# Element-wise multiplication of matrices with different dimension

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.

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

• Thanks for the powerful answer! Commented Mar 20, 2019 at 23:03
• You're welcome. Commented Mar 20, 2019 at 23:04
• 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. Commented Mar 23, 2019 at 6:56
• Yeah. In this sense, CompiledFunctions work slightly differently but IMHO more predictably than conventional function with the attribute Listable. Commented Mar 23, 2019 at 7:27

Using Map:

Result = mat2*# & /@ mat1


This can be parallelized for large systems:

Result = Parallelize[mat2*# & /@ mat1]

• 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... Commented Mar 22, 2019 at 10:44
• Yes @HenrikSchumacher I have found the same bizarre result as you. Plus, none of my methods are as fast as yours. Commented Mar 22, 2019 at 10:49