{"id":28,"date":"2006-03-22T11:54:54","date_gmt":"2006-03-22T16:54:54","guid":{"rendered":"https:\/\/blogs.mathworks.com\/loren\/?p=28"},"modified":"2018-01-18T16:16:27","modified_gmt":"2018-01-18T21:16:27","slug":"making-functions-suitable-for-nd-arrays","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/loren\/2006\/03\/22\/making-functions-suitable-for-nd-arrays\/","title":{"rendered":"Making Functions Suitable for ND Arrays"},"content":{"rendered":"<style xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\">\r\n\r\npre.codeinput {\r\n  background: #F9F7F3;\r\n  padding: 10px;\r\n  border: 1px solid rgb(200,200,200);\r\n}\r\n\r\n@media print {\r\n  pre.codeinput {word-wrap:break-word; width:100%;}\r\n} \r\n\r\nspan.keyword {color: #0000FF}\r\nspan.comment {color: #228B22}\r\nspan.string {color: #A020F0}\r\nspan.untermstring {color: #B20000}\r\nspan.syscmd {color: #B28C00}\r\n\r\npre.codeoutput {\r\n  background: #F9F7F3;\r\n  color: #777777;\r\n  padding: 10px;\r\n  border: 1px solid rgb(200,200,200);\r\n}\r\n\r\npre.error {\r\n  color: red;\r\n}\r\n\r\np.footer {\r\n  text-align: right;\r\n  font-size: xx-small;\r\n  font-weight: lighter;\r\n  font-style: italic;\r\n  color: gray;\r\n}\r\n\r\n  <\/style><div xmlns:mwsh=\"https:\/\/www.mathworks.com\/namespace\/mcode\/v1\/syntaxhighlight.dtd\" class=\"content\">\r\n   <introduction>\r\n      <p>When we changed MATLAB to handle more than just 2-dimensional arrays (MATLAB version 5), we wanted to extend existing M-files\r\n         to also handle N dimensions, when sensible.  We found certain ways to do that well and I plan to show a couple of the techniques\r\n         here.\r\n      <\/p>\r\n   <\/introduction>\r\n   <h3>Contents<\/h3>\r\n   <div>\r\n      <ul>\r\n         <li><a href=\"#1\">Reshape into a 2-Dimensional Array<\/a><\/li>\r\n         <li><a href=\"#4\">Use a List of N-Dimensional Indices<\/a><\/li>\r\n         <li><a href=\"#9\">Two Techniques for Handling N-D Arrays<\/a><\/li>\r\n      <\/ul>\r\n   <\/div>\r\n   <h3>Reshape into a 2-Dimensional Array<a name=\"1\"><\/a><\/h3>\r\n   <p>The formula for this technique is: * Reshape input into a 2-D array * Set up output array * Work on the columns * Reset the\r\n      output shape if shape wasn't set up earlier\r\n   <\/p>\r\n   <p>For an example of this technique, let's looks at the function <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/mode.html\"><tt>mode<\/tt><\/a> and a few lines in particular.  You will see similar code in the function <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/trapz.html\"><tt>trapz<\/tt><\/a>. The first thing you see in the code is error checking inputs and validating the dimension to operate on and setting up information\r\n      to collect the correct output (i.e., how many outputs is the user asking for and should any of them be sparse?).  We then\r\n      reach lines 114:117\r\n   <\/p><pre class=\"codeinput\">dbtype <span class=\"string\">mode<\/span> <span class=\"string\">114:117<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n114   % Convert data to operate along columns of a 2-d array\r\n115   x = permute(x,[dim, (1:dim-1), (dim+1:length(sizex))]);\r\n116   x = reshape(x,[sizex(dim),prod(sizem)]);\r\n117   [nrows,ncols] = size(x);\r\n\r\n<\/pre><p>where we reshape the data into a 2-D matrix.  We are now ready to calculate the mode.  In this case, we don't need to reshape\r\n      the output, because it was set up initially to be the right dimensions.  And the mode calculation itself places the output\r\n      value into the array using linear indexing. Linear indexing does not alter the shape of the array being operated on, so the output shape, which was preset, is preserved\r\n      in this case.\r\n   <\/p>\r\n   <h3>Use a List of N-Dimensional Indices<a name=\"4\"><\/a><\/h3>\r\n   <p>Instead of reshaping the array, another technique is to perform N-dimensional indexing.  Here I'll show some of the code in\r\n      the function <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/fftshift.html\"><tt>fftshift<\/tt><\/a> where we want to work on all the elements unchanged in all dimensions except one.  And in that dimension, we do something\r\n      specific.  Let's look at some of the code:\r\n   <\/p><pre class=\"codeinput\">dbtype <span class=\"string\">fftshift<\/span> <span class=\"string\">23:31<\/span>\r\n<\/pre><pre class=\"codeoutput\">\r\n23    if nargin &gt; 1\r\n24        if (~isscalar(dim)) || floor(dim) ~= dim || dim &lt; 1\r\n25            error('MATLAB:fftshift:DimNotPosInt', 'DIM must be a positive integer.')\r\n26        end\r\n27        idx = repmat({':'}, 1, max(ndims(x),dim));\r\n28        m = size(x, dim);\r\n29        p = ceil(m\/2);\r\n30        idx{dim} = [p+1:m 1:p];\r\n31    else\r\n\r\n<\/pre><p>First we find out what dimension is of interest.  We then create a cell array , to be used later for indexing, and we fill\r\n      it with <tt>':'<\/tt> through the maximum of the dimension of interest and the dimension of the input array (in this case, to allow for possible\r\n      extra dimensions with size 1).  We now have a cell array filled with <tt>':'<\/tt> and we replace the single entry for the dimension of interest with some other values, in this case, we swap the first half\r\n      of the existing values in <tt>1:m<\/tt> with the second half.\r\n   <\/p>\r\n   <p>Suppose <tt>A<\/tt> is 4-dimensional where the 3rd dimension is the one of interest and is length 4. Our cell array, <tt>indices<\/tt>, would now look like this:\r\n   <\/p><pre class=\"codeinput\">swapind = [3:4 1:2]\r\nindices = {<span class=\"string\">':'<\/span>,<span class=\"string\">':'<\/span>,swapind,<span class=\"string\">':'<\/span>}\r\n<\/pre><pre class=\"codeoutput\">\r\nswapind =\r\n\r\n     3     4     1     2\r\n\r\n\r\nindices = \r\n\r\n    ':'    ':'    [1x4 double]    ':'\r\n\r\n<\/pre><p>And now we are ready to rearrange the contents of <tt>A<\/tt>, but taking advantage of ability to turn a cell array into comma-separated list.\r\n   <\/p><pre class=\"codeinput\">A = rand(2,1,4,2);\r\nB = A(indices{:});\r\n<\/pre><p>You might want to compare <tt>A<\/tt> and <tt>B<\/tt> here.  I'll just compare the first page of <tt>A<\/tt> and the relevant page of <tt>B<\/tt>.\r\n   <\/p><pre class=\"codeinput\">[A(:,:,1,2)  B(:,:,3,2)]\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n    0.8983    0.8983\r\n    0.7546    0.7546\r\n\r\n<\/pre><h3>Two Techniques for Handling N-D Arrays<a name=\"9\"><\/a><\/h3>\r\n   <p>I've illustrated two techniques for handling N-dimensional arrays. * Reshape arrays into 2-D arrays and reshape the output\r\n      appropriately * Use indexing, perhaps with <tt>':'<\/tt>, and comma-separated lists to get the desired results.\r\n   <\/p>\r\n   <p>You can also work some indexing magic using <a href=\"\">anonymous functions<\/a>. Do you know of other techniques?  If so, add them \r\n<a href=\"https:\/\/blogs.mathworks.com\/loren\/?p=28#respond\">here<\/a>.\r\n   <\/p>\r\n   <p class=\"footer\"><br>\r\n      Published with MATLAB&reg; 7.2<br><\/p>\r\n<\/div>\r\n<!--\r\n##### SOURCE BEGIN #####\r\n%% Making Functions Suitable for ND Arrays\r\n% When we changed MATLAB to handle more than just 2-dimensional arrays\r\n% (MATLAB version 5), we wanted to extend existing M-files to also handle\r\n% N dimensions, when sensible.  We found certain ways to do that well and I\r\n% plan to show a couple of the techniques here.\r\n\r\n%% Reshape into a 2-Dimensional Array\r\n% The formula for this technique is:\r\n% * Reshape input into a 2-D array\r\n% * Set up output array\r\n% * Work on the columns\r\n% * Reset the output shape if shape wasn't set up earlier\r\n%%\r\n% For an example of this technique, let's looks at the function\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/mode.html |mode|>\r\n% and a few lines in particular.  You will see similar code in the function\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/trapz.html |trapz|>.\r\n% The first thing you see in the code is error checking inputs and\r\n% validating the dimension to operate on and setting up information to\r\n% collect the correct output (i.e., how many outputs is the user asking\r\n% for and should any of them be sparse?).  We then reach lines 114:117\r\ndbtype mode 114:117\r\n%%\r\n% where we reshape the data into a 2-D matrix.  We are now ready to\r\n% calculate the mode.  In this case, we don't need to reshape the output,\r\n% because it was set up initially to be the right dimensions.  And the mode\r\n% calculation itself places the output value into the array using\r\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/matlab_prog\/f1-85511.html linear indexing>.\r\n% Linear indexing does not alter the shape of the array being operated on,\r\n% so the output shape, which was preset, is preserved in this case.\r\n\r\n%% Use a List of N-Dimensional Indices\r\n% Instead of reshaping the array, another technique is to perform\r\n% N-dimensional indexing.  Here I'll show some of the code in the function\r\n% <https:\/\/www.mathworks.com\/help\/matlab\/ref\/fftshift.html |fftshift|>\r\n% where we want to work on all the elements unchanged in all dimensions\r\n% except one.  And in that dimension, we do something specific.  Let's\r\n% look at some of the code:\r\ndbtype fftshift 23:31\r\n%%\r\n% First we find out what dimension is of interest.  We then create\r\n% a cell array , to be used later for indexing, and we fill it with |':'|\r\n% through the maximum of the dimension of interest and the dimension of the\r\n% input array (in this case, to allow for possible extra dimensions with\r\n% size 1).  We now have a cell array filled with |':'| and we replace the\r\n% single entry for the dimension of interest with some other values, in\r\n% this case, we swap the first half of the existing values in |1:m| with\r\n% the second half.  \r\n%%\r\n% Suppose |A| is 4-dimensional where the 3rd dimension is the one of interest\r\n% and is length 4.\r\n% Our cell array, |indices|, would now might look like this:\r\nswapind = [3:4 1:2]\r\nindices = {':',':',swapind,':'}\r\n%%\r\n% And now we are ready to rearrange the contents of |A|, but taking\r\n% advantage of ability to turn a cell array into a\r\n% <https:\/\/www.mathworks.com\/access\/helpdesk\/help\/techdoc\/matlab_prog\/f0-48002.html comma-separated list>.\r\nA = rand(2,1,4,2);\r\nB = A(indices{:});\r\n%%\r\n% You might want to compare |A| and |B| here.  I'll just compare the first\r\n% page of |A| and the relevant page of |B|.\r\n[A(:,:,1,2)  B(:,:,3,2)]\r\n%% Two Techniques for Handling N-D Arrays\r\n% I've illustrated two techniques for handling N-dimensional arrays.\r\n% * Reshape arrays into 2-D arrays and reshape the output appropriately\r\n% * Use indexing, perhaps with |':'|, and comma-separated lists to get the\r\n% desired results.\r\n%%\r\n% You can also work some indexing magic using \r\n% < anonymous functions>.\r\n% Do you know of other techniques?  If so, add them \r\n% <https:\/\/blogs.mathworks.com\/loren\/?p=28#comments here a>.\r\n\r\n##### SOURCE END #####\r\n-->","protected":false},"excerpt":{"rendered":"<p>\r\n\r\npre.codeinput {\r\n  background: #F9F7F3;\r\n  padding: 10px;\r\n  border: 1px solid rgb(200,200,200);\r\n}\r\n\r\n@media print {\r\n  pre.codeinput {word-wrap:break-word; width:100%;}\r\n} \r\n\r\nspan.keyword... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/loren\/2006\/03\/22\/making-functions-suitable-for-nd-arrays\/\">read more >><\/a><\/p>","protected":false},"author":39,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/28"}],"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=28"}],"version-history":[{"count":2,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/28\/revisions"}],"predecessor-version":[{"id":2654,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/posts\/28\/revisions\/2654"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/media?parent=28"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/categories?post=28"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/loren\/wp-json\/wp\/v2\/tags?post=28"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}