{"id":149,"date":"2008-08-04T07:21:14","date_gmt":"2008-08-04T12:21:14","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/2008\/08\/04\/comparing-repmat-and-bsxfun-performance\/"},"modified":"2017-06-07T21:16:38","modified_gmt":"2017-06-08T02:16:38","slug":"comparing-repmat-and-bsxfun-performance","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2008\/08\/04\/comparing-repmat-and-bsxfun-performance\/","title":{"rendered":"Comparing repmat and bsxfun Performance"},"content":{"rendered":"<div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <introduction>\r\n      <p>I've been asked repeatedly about the performance comparison between two MATLAB functions, <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/bsxfun.html\"><tt>bsxfun<\/tt><\/a> and <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/repmat.html\"><tt>repmat<\/tt><\/a>. These two functions can each help with calculations in which two arrays are expected to have the same dimensions, but some\r\n         of the input dimensions, instead of agreeing, may have the value 1.  The simple example I use here is subtracting the columns\r\n         means from a matrix.\r\n      <\/p>\r\n   <\/introduction>\r\n   <h3>Contents<\/h3>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"#1\">Setup<\/a><\/li>\r\n         <li><a href=\"#2\">Code I'm Tempted to Write<\/a><\/li>\r\n         <li><a href=\"#4\">Timing repmat<\/a><\/li>\r\n         <li><a href=\"#5\">Indexing with ones<\/a><\/li>\r\n         <li><a href=\"#6\">Timing Indexing<\/a><\/li>\r\n         <li><a href=\"#8\">Timing bsxfun<\/a><\/li>\r\n         <li><a href=\"#9\">Punchline<\/a><\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <h3>Setup<a name=\"1\"><\/a><\/h3>\r\n   <p>First I set up the data.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">m = 1e5;\r\nn = 100;\r\nA = rand(m,n);<\/pre><h3>Code I'm Tempted to Write<a name=\"2\"><\/a><\/h3>\r\n   <p>And now here's the code I'm tempted to write, safely tucked inside the confines of a <tt>try<\/tt> statement.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\"><span style=\"color: #0000FF\">try<\/span>\r\n    AZeroMean = A - mean(A);\r\n<span style=\"color: #0000FF\">catch<\/span> ME\r\n    disp(ME.message);\r\n<span style=\"color: #0000FF\">end<\/span><\/pre><pre style=\"font-style:oblique\">Matrix dimensions must agree.\r\n<\/pre><p>As you can see, MATLAB does not allow binary operators to work on arrays with different sizes (except when one of the inputs\r\n      is a scalar value). There are at least two ways to remedy this.\r\n   <\/p>\r\n   <li>Store the intermediate calculation from <tt>mean(A)<\/tt> in a vector and then create a new array the same size as <tt>A<\/tt> with replicates of the row vector from the <tt>mean<\/tt>. You can do this with <tt>repmat<\/tt> or via indexing an appropriate number of times into the row of this vector.\r\n   <\/li>\r\n   <li>Call <tt>bsxfun<\/tt> with the appropriate two inputs and allow it to perform the equivalent singleton dimension expansion.  The nice thing about\r\n      this is there is no need for a large intermediate array the same size as <tt>A<\/tt>. A possible downside, especially since <tt>bsxfun<\/tt> is relatively new, is that the code doesn't, at first reading, appear as obvious.\r\n   <\/li>\r\n   <h3>Timing repmat<a name=\"4\"><\/a><\/h3>\r\n   <p>Using the most excellent <tt>timeit<\/tt> utility that Steve Eddins posted to the file exchange, I now time the <tt>repmat<\/tt> calculations.  First I create an anonymous function that does my calculation.  Then I pass that function handle to <tt>timeit<\/tt>.  <tt>timeit<\/tt> carefully warms up the function by running it enough so the times are not subject to first-time effects, figuring out how\r\n      many times to run it to get meaningful results, and more.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">frepmat = @() A - repmat(mean(A),size(A,1),1);\r\ntimeit(frepmat)<\/pre><pre style=\"font-style:oblique\">ans =\r\n      0.30964\r\n<\/pre><h3>Indexing with ones<a name=\"5\"><\/a><\/h3>\r\n   <p><tt>repmat<\/tt> uses a variety of techniques for replicating an array, depending on the details of what's being replicated.  One technique\r\n      is to index into the array with ones in the dimension to replicate.  Here's an illustative example with a vector.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">q = [17 pi 42 exp(1)];\r\nq5 = repmat(q,5,1)<\/pre><pre style=\"font-style:oblique\">q5 =\r\n           17       3.1416           42       2.7183\r\n           17       3.1416           42       2.7183\r\n           17       3.1416           42       2.7183\r\n           17       3.1416           42       2.7183\r\n           17       3.1416           42       2.7183\r\n<\/pre><h3>Timing Indexing<a name=\"6\"><\/a><\/h3>\r\n   <p>One thing I notice with the <tt>repmat<\/tt> solution is that I need to create the vector <tt>mean(A)<\/tt> for the function.  I need to do the same thing without <tt>repmat<\/tt> and I want to be able to set up one function call for performing the calculation so I can use <tt>timeit<\/tt>.  Since I can't index into the results of a function without assigning the output to a variable, I create an intermediate\r\n      function <tt>meanones<\/tt> to help.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">type <span style=\"color: #A020F0\">meanones<\/span><\/pre><pre style=\"font-style:oblique\">\r\nfunction y = meanones(A)\r\n\r\nmn = mean(A);\r\ny = A - mn(ones(1,size(A,1)),:);\r\n\r\n<\/pre><p>Now I'm ready to do the timing.<\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">findex = @() meanones(A);\r\ntimeit(findex)<\/pre><pre style=\"font-style:oblique\">ans =\r\n      0.31389\r\n<\/pre><h3>Timing bsxfun<a name=\"8\"><\/a><\/h3>\r\n   <p>Next see the timing calculation done using <tt>bsxfun<\/tt>.\r\n   <\/p><pre style=\"background: #F9F7F3; padding: 10px; border: 1px solid rgb(200,200,200)\">fbsxfun = @() bsxfun(@minus,A,mean(A));\r\ntimeit(fbsxfun)<\/pre><pre style=\"font-style:oblique\">ans =\r\n      0.20569\r\n<\/pre><h3>Punchline<a name=\"9\"><\/a><\/h3>\r\n   <p>In this example, <tt>bsxfun<\/tt> performs fastest.  Now that you see <tt>bsxfun<\/tt> in action, can you think of uses for this function in your work?  Let me know <a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=149#respond\">here<\/a>.\r\n   <\/p><script language=\"JavaScript\">\r\n<!--\r\n\r\n    function grabCode_d8100c6b57cd46799bfa6cdc251183ef() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='d8100c6b57cd46799bfa6cdc251183ef ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' d8100c6b57cd46799bfa6cdc251183ef';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        author = 'Loren Shure';\r\n        copyright = 'Copyright 2008 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add author and copyright lines at the bottom if specified.\r\n        if ((author.length > 0) || (copyright.length > 0)) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (author.length > 0) {\r\n                d.writeln('% _' + author + '_');\r\n            }\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n      \r\n      d.title = title + ' (MATLAB code)';\r\n      d.close();\r\n      }   \r\n      \r\n-->\r\n<\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_d8100c6b57cd46799bfa6cdc251183ef()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n            the MATLAB code \r\n            <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; 7.6<br><\/p>\r\n<\/div>\r\n<!--\r\nd8100c6b57cd46799bfa6cdc251183ef ##### SOURCE BEGIN #####\r\n%% Comparing repmat and bsxfun Performance\r\n% I've been asked repeatedly about the performance comparison between two\r\n% MATLAB functions, <https:\/\/www.mathworks.com\/help\/matlab\/ref\/bsxfun.html |bsxfun|> \r\n% and <https:\/\/www.mathworks.com\/help\/matlab\/ref\/repmat.html |repmat|>.\r\n% These two functions can each help with calculations in which two arrays\r\n% are expected to have the same dimensions, but some of the input\r\n% dimensions, instead of agreeing, may have the value 1.  The simple\r\n% example I use here is subtracting the columns means from a matrix.\r\n%% Setup\r\n% First I set up the data.\r\nm = 1e5;\r\nn = 100;\r\nA = rand(m,n);\r\n%% Code I'm Tempted to Write\r\n% And now here's the code I'm tempted to write, safely tucked inside the\r\n% confines of a |try| statement.\r\ntry\r\n    AZeroMean = A - mean(A);\r\ncatch ME\r\n    disp(ME.message);\r\nend\r\n%%\r\n% As you can see, MATLAB does not allow binary operators to work on arrays\r\n% with different sizes (except when one of the inputs is a scalar value).\r\n% There are at least two ways to remedy this.  \r\n%\r\n% # Store the intermediate calculation from |mean(A)| in a vector and then\r\n% create a new array the same size as |A| with replicates of the row vector\r\n% from the |mean|. You can do this with |repmat| or via indexing an\r\n% appropriate number of times into the row of this vector.\r\n% # Call |bsxfun| with the appropriate two inputs and allow it to perform\r\n% the equivalent singleton dimension expansion.  The nice thing about this\r\n% is there is no need for a large intermediate array the same size as |A|.\r\n% A possible downside, especially since |bsxfun| is relatively new, is that\r\n% the code doesn't, at first reading, appear as obvious.\r\n%% Timing repmat\r\n% Using the most excellent\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/loadFile.do?objectId=18798&objectType=file |timeit|> \r\n% utility that Steve Eddins posted to the file exchange, I now time the\r\n% |repmat| calculations.  First I create an anonymous function that does my\r\n% calculation.  Then I pass that function handle to |timeit|.  |timeit|\r\n% carefully warms up the function by running it enough so the times are not\r\n% subject to first-time effects, figuring out how many times to run it to\r\n% get meaningful results, and more.\r\nfrepmat = @() A - repmat(mean(A),size(A,1),1);\r\ntimeit(frepmat)\r\n\r\n%% Indexing with ones\r\n% |repmat| uses a variety of techniques for replicating an array, depending\r\n% on the details of what's being replicated.  One technique is to index\r\n% into the array with ones in the dimension to replicate.  Here's an\r\n% illustative example with a vector.\r\nq = [17 pi 42 exp(1)];\r\nq5 = repmat(q,5,1)\r\n%% Timing Indexing\r\n% One thing I notice with the |repmat| solution is that I need to create\r\n% the vector |mean(A)| for the function.  I need to do the same thing\r\n% without |repmat| and I want to be able to set up one function call for \r\n% performing the calculation so I can use |timeit|.  Since I can't index\r\n% into the results of a function without assigning the output to a\r\n% variable, I create an intermediate function |meanones| to help.\r\ntype meanones\r\n%%\r\n% Now I'm ready to do the timing.\r\nfindex = @() meanones(A);\r\ntimeit(findex)\r\n%% Timing bsxfun\r\n% Next see the timing calculation done using |bsxfun|.\r\nfbsxfun = @() bsxfun(@minus,A,mean(A));\r\ntimeit(fbsxfun)\r\n%% Punchline\r\n% In this example, |bsxfun| performs fastest.  Now that you see |bsxfun| in\r\n% action, can you think of uses for this function in your work?  Let me\r\n% know <https:\/\/blogs.mathworks.com\/loren\/?p=149#respond here>.\r\n\r\n\r\n##### SOURCE END ##### d8100c6b57cd46799bfa6cdc251183ef\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n   \r\n      I've been asked repeatedly about the performance comparison between two MATLAB functions, bsxfun and repmat. These two functions can each help with calculations in which two arrays are... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2008\/08\/04\/comparing-repmat-and-bsxfun-performance\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[16,10,15,6],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/149"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/comments?post=149"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/149\/revisions"}],"predecessor-version":[{"id":2363,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/149\/revisions\/2363"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}