Skip to Main Content Skip to Search
File Exchange
MATLAB Newsgroup
Link Exchange
  Blogs  
 Contest 
MathWorks.com

Loren on the Art of MATLAB

March 22nd, 2006

Making Functions Suitable for ND Arrays

When we changed MATLAB to handle more than just 2-dimensional arrays (MATLAB version 5), we wanted to extend existing M-files 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 here.

Contents

Reshape into a 2-Dimensional Array

The formula for this technique is: * Reshape input into a 2-D array * Set up output array * Work on the columns * Reset the output shape if shape wasn't set up earlier

For an example of this technique, let's looks at the function mode and a few lines in particular. You will see similar code in the function trapz. The first thing you see in the code is error checking inputs and validating the dimension to operate on and setting up information to collect the correct output (i.e., how many outputs is the user asking for and should any of them be sparse?). We then reach lines 114:117

dbtype mode 114:117
114   % Convert data to operate along columns of a 2-d array
115   x = permute(x,[dim, (1:dim-1), (dim+1:length(sizex))]);
116   x = reshape(x,[sizex(dim),prod(sizem)]);
117   [nrows,ncols] = size(x);

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 the output, because it was set up initially to be the right dimensions. And the mode calculation itself places the output 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 in this case.

Use a List of N-Dimensional Indices

Instead of reshaping the array, another technique is to perform N-dimensional indexing. Here I'll show some of the code in the function fftshift where we want to work on all the elements unchanged in all dimensions except one. And in that dimension, we do something specific. Let's look at some of the code:

dbtype fftshift 23:31
23    if nargin > 1
24        if (~isscalar(dim)) || floor(dim) ~= dim || dim < 1
25            error('MATLAB:fftshift:DimNotPosInt', 'DIM must be a positive integer.')
26        end
27        idx = repmat({':'}, 1, max(ndims(x),dim));
28        m = size(x, dim);
29        p = ceil(m/2);
30        idx{dim} = [p+1:m 1:p];
31    else

First we find out what dimension is of interest. We then create a cell array , to be used later for indexing, and we fill it with ':' through the maximum of the dimension of interest and the dimension of the input array (in this case, to allow for possible extra dimensions with size 1). We now have a cell array filled with ':' and we replace the single entry for the dimension of interest with some other values, in this case, we swap the first half of the existing values in 1:m with the second half.

Suppose A is 4-dimensional where the 3rd dimension is the one of interest and is length 4. Our cell array, indices, would now look like this:

swapind = [3:4 1:2]
indices = {':',':',swapind,':'}
swapind =

     3     4     1     2


indices = 

    ':'    ':'    [1x4 double]    ':'

And now we are ready to rearrange the contents of A, but taking advantage of ability to turn a cell array into a comma-separated list.

A = rand(2,1,4,2);
B = A(indices{:});

You might want to compare A and B here. I'll just compare the first page of A and the relevant page of B.

[A(:,:,1,2)  B(:,:,3,2)]
ans =

    0.8983    0.8983
    0.7546    0.7546

Two Techniques for Handling N-D Arrays

I've illustrated two techniques for handling N-dimensional arrays. * Reshape arrays into 2-D arrays and reshape the output appropriately * Use indexing, perhaps with ':', and comma-separated lists to get the desired results.

You can also work some indexing magic using anonymous functions. Do you know of other techniques? If so, add them here.

4 Responses to “Making Functions Suitable for ND Arrays”

  1. John D'Errico replied on :

    Another approach is to use the abilities of arrayfun and cellfun to extend existing codes to higher dimensions. For example, break your array into
    a cell array using mat2cell. Then use cellfun to apply some function of your choosing, and aggregate the results as appropriate.
    John

  2. SRL replied on :

    I often use the technique that John mentions. I think having a function with the flexibility of cellfun but loops over a dimension would be ideal. for example: rowfun would pass each row one by one into @yourfun, columnfun would do the same for each column. This way, data does not need to be replicated, converted to cellarrays, etc.. just to provide this looping mechanism.

    I don’t just suggest we have a rowfun and columnfun but rather a generic function (maybe DIMFUN) that allows us to loop over any dimesion. If we were looping over the third dimesion of a 3d matrix, I would want the slice to first pass through squeeze to convert it into a 2d slice rather then still be in 3d.

    Just an idea that I think the Matlab community could benefit from.

    SRL

  3. C Rose replied on :

    I’ve recently implemented some code to handle arbitrary-dimensional data, and used yet another approach.

    My solution is perhaps a bit ‘hackish’, but it works quite well. I wanted to be able to index an array called obj in the following ways (example is with obj being 2D):

    obj(1:2:end, 1:2:end)
    obj(1:2:end, 2:2:end)
    obj(2:2:end, 1:2:end)
    obj(2:2:end, 2:2:end)

    For 3D it would be obj(1:2:end, 1:2:end, 1:2:end) etc. and there would be 2^3 combinations.

    I used base-2 counting (via Matlab’s DEC2BIN) to enumerate the combinations and the actual indexing on obj was achieved by creating a string (e.g. ‘obj(1:2:end, 1:2:end)’) and then calling Matlab’s EVAL on that string.

    The advantages of this method are:

    one doesn’t have to learn a new syntax for indexing (I’ve been using Matlab for years and didn’t know of Loren’s cell array-based method, and it wouldn’t have occurred to me);

    by generating strings, which are then evaluated, it’s easy to see exactly what would be computed (though actually the cell array method is equally transparent once you know about it).

    I imagined the main disadvantage would be the performance hit of making Matlab to interpret code at run-time, however profiling on simple examples shows that there doesn’t appear to be a massive performance hit compared to some of the other Matlab functions I’m using (e.g. REGRESS, PADARRAY) in the code.

    It would be interesting to know more about EVAL.

  4. sridharan kamalakannan replied on :

    Hi Loren,

    I have a stack of 2D polygons. Can u suggest me a way to stack these polygons in 3D such that I get a 3D object out of these 2D polygons.

Leave a Reply


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Ulla Vainio: That error bar width adjustment was extremely useful and I would never have figured it out myself....
  • Peter Perkins: Jessee, there is a property that you can use to tag variables with units. For example, >> load...
  • Jessee: I could potentially see myself using dataset for casually looking at data, but from an application standpoint...
  • Loren: Oktay- It very much depends on the details of the calculations you are doing. Vectorization can sometimes...
  • Oktay: Hello, Is there any significant difference between using: - Vectorization inside a subfunction - Benefiting...
  • Loren: Clare- Yes, sum can sum a double vector: x = [.3 .4 pi/3] y = sum(x) x = 0.3 0.4 1.0472 y = 1.7472 You must...
  • Clare J: R2007a - Student Version When I use sum to sum a vector of type double I get this error message: ???...
  • Sarah Zaranek: Hi Jacob, Sorry about the slow response. You are correct that the code would be slower without the...
  • Navaneethan Santhanam: Thanks a lot, Loren! That worked perfectly.
  • Mike N: Should it be OK to use “persistent 221; variables in a deployed application? What if I have two...

These postings are the author's and don't necessarily represent the opinions of The MathWorks.

Related Topics