Loren on the Art of MATLAB

Turn ideas into MATLAB

Importance of Implicit Expansion For Performance

Sometimes people state that they like using MATLAB because it's easy to express their mathematical thoughts. Sometimes there's a follow-on that they then switch to another language for performance. While early in the history of MATLAB, that was sometimes beneficial, it is not so obvious these days. Let's take the example of implicit expansion (also here).

To maximize the benefits of implicit expansion, it's best if you have a more complicated, computationally expensive expression for MATLAB to work with while minimizing the need for temporary arrays. MATLAB can then exploit coarse grain parallelism. But it also depends on your computer and the array sizes you are using. And it's worth thinking about code maintenance (for the future) and its complexity/simplicity.



Here is demonstration of this simple idea. I'm testing equivalent numerical algorithms for removing the mean of any array and scaling it. Below are three equivalent implementations in MATLAB, the last one embeds a possible temporary array into one single line to take advantage of the most magic possible. The first one uses the well-named bsxfun function. The second one uses the same steps as the first, but uses implicit expansion instead. And the third method combines some of the steps so there are fewer overall statements. I'm calling this one smart.

n = [300, 1000, 3000, 10000];
alltimes = zeros(length(n),4);
%alltimes = table( "size", [length(n),4],...
%    "VariableNames",["n", "bsxfun", "implicit","smart"]);
for i = 1:length(n)
   runtimes = testRemoveMeanAndScale(n(i));
   alltimes(i,:) = [n(i), runtimes];
format short g
alltimesT = array2table(alltimes,"VariableNames",["n", "bsxfun", "implicit","smart"])
alltimesT =
  4×4 table
      n        bsxfun       implicit       smart   
    _____    __________    __________    __________
      300    0.00024632    0.00014821    7.5306e-05
     1000       0.00322     0.0036559     0.0027499
     3000      0.030063      0.036868      0.027908
    10000        0.3469       0.38712       0.33361


You can see that the timings are not completely consistent. It appears that as the arrays get larger, the smart algorithm consistently outperforms the other ones. Implicit expansion and bsxfun are generally on par except for small matrix sizes, where perhaps the extra function call costs enough extra to be noticeable.

Which Code Do You Prefer, and Why?

I'm wondering which code you'd prefer and I'd love to hear your reasons. Let me know here.

%% Test Functions
function runtime = testRemoveMeanAndScale(n)
% This function tests the 3 algorithms we wish to compare w.r.t. speed.
X = rand(n);
mu = rand(1,n);
sigma = randi([0 1],1,n);
runtime(1) = timeit(@()bsxfunRemoveMeanAndScale(X, mu, sigma));
runtime(2) = timeit(@()implicitExpansionRemoveMeanAndScale(X, mu, sigma));
runtime(3) = timeit(@()smartRemoveMeanAndScale(X, mu, sigma));
end % testRemoveMeanAndScale

function X = bsxfunRemoveMeanAndScale(X, mu, sigma) 
% Implementation using bsxfun
X = bsxfun(@minus, X, mu);
sigma(sigma==0) = 1;
X = bsxfun(@rdivide, X, sigma);
end % bsxfunRemoveMeanAndScale
function X = implicitExpansionRemoveMeanAndScale(X, mu, sigma) 
% Use implicit expansion 
X = X - mu;
sigma(sigma==0) = 1;
X = X ./ sigma;
end % implicitExpansionRemoveMeanAndScale
function X = smartRemoveMeanAndScale(X, mu, sigma) 
% Recommended implicit expansion implementation
sigma(sigma==0) = 1;
X = (X - mu)./ sigma;
end % smartRemoveMeanAndScale

Published with MATLAB® R2019b

  • print
  • send email


To leave a comment, please click here to sign in to your MathWorks Account or create a new one.