File Exchange

## sub2allind

version 1.5 (2.69 KB) by

convert subscripts to ALL corresponding indices

Updated

idx = sub2allind(sz, sub1, sub2, sub3, ... )

Like Matlab's sub2ind, sub2allind computes the equivalent linear indices for
given subscripts of an array with size SZ.
Unlike sub2ind, it computes a field of all combinations of
subscripts. So, instead of calling A( 2:3, 1, 4:11) you might
use
linIdx = sub2allind( size(A), 2:3, 1, 4:11 );

and then call A(linIdx) or A(linIdx(:)) or you reshape linIdx the way you need.

This is usefull whenever you want to access a subset of an array and compare it with a differently shaped thing, like

A(linIdx(:)) = A(linIdx(:)) + <1D-Vector>

Using the naked colon operator is allowed to reference an entire dimension:

linIdx = sub2allind( sz, :, sub2 );

Yung-Yeh Chang

### Yung-Yeh Chang (view profile)

I was about to write something similar to this and yet something even better is already here. Great job.

Alexander Stepanov

### Alexander Stepanov (view profile)

Very useful, thanks)

Marc

Matt J

### Matt J (view profile)

"I wonder if it would be best to make that behaviour default, since you could nevertheless use linIdx(:) if you want it to be a vector."

Perhaps, although if other people have downloaded previous versions of the tool, they might have backward compatibility issues.

Michael Völker

### Michael Völker (view profile)

Matt, the reshape thing is the easiest, since the indices happen to automatically be in the right shape (plus 1 leading "dummy dimension") before I convert them to a column vector.
I wonder if it would be best to make that behaviour default, since you could nevertheless use linIdx(:) if you want it to be a vector.

Matt J

### Matt J (view profile)

I like it. It's occurred to me that it will be a good OOP tool for converting the output of the SUBSTRUCT function to a linear index. All the more reason why processing ':' is a good thing. This often comes up in OOP applications where you want to overload SUBSREF or SUBSASGN.

One more tip I had was to enable a syntax
similar to

linIdx=sub2inall('reshape',size(A),2:3,1,4:11)

which would automatically reshape linIdx to be the same shape as A(2:3,1,4:11). That way, A(linIdx) and A(2:3,1,4:11) would produce exactly the same result (in shape as well as in data content).

Michael Völker

### Michael Völker (view profile)

(Narf, I meant of course sub2allind(sz,2:3,':'), not A...)

Michael Völker

### Michael Völker (view profile)

Jos, your ngrid-approach is very cool. The only reason I still do not use it is that it still may explode the memory and take quite long, if the requested field of indices itself is very large.
If the array has N dimensions, ngrid will produce N new arrays each the size of the requested field of subscripts. However, as bsxfun is a quite young function, the ngrid approach should be much more portable.

To be honest, I hardly remember where I used this function the last time, but I think it was at some point where I later figured out I could use accumarray() instead of whatever I tried before. But what I know for sure is that the default sub2ind-behaviour *always* bugged me, because it is simply not what I'd expect from it.
So the primary reason for me to code this, was that I have this functionality I expect, or at least have a sneak in the source later, when I forgot how it works. :-)

Matt, I like your remark, so I utilize ':' now. The funny thing is, that not only A(sz,2:3,':') works, but A(sz,2:3,:) is okay, too. Somehow, the colon seems to become a string, automagically...

Matt J

### Matt J (view profile)

You might want to consider allowing ':' inputs as well. For example, if you want the linear index corresponding to
A(2:3,:,4:11) then you would call

linIdx = sub2allind( size(A), 2:3, ':', 4:11 );

Also, perhaps I'm not seeing all of the situations where you intend to use this, however, I tend to think that you'll save yourself both CPU time and memory if instead of linear indexing A, you simply reshape your 1D-Vector .

Jos (10584)

### Jos (10584) (view profile)

Sure, for large arrays, the logical-find method is a waste of memory, especially if you only need a few indices ...
Another, fast and vectorized, option:

function idx = sub2allind(sz, varargin)
[subix{1:nargin-1}] = ndgrid(varargin{:}) ;
idx = sub2ind(sz,subix{:}) ;

Michael Völker

### Michael Völker (view profile)

Oops, nice... :-)

I had the feeling there should be an easier way...

But nevertheless, I usually work with quite large arrays (some 1E8 entries), where your admittedly very nice code causes a waste of RAM and time since an equal-sized array must be actually created.

With sz=[1E3 1E3 1E3], my version needs about 0.000478 seconds, the find-version takes 1.412256 seconds.

Jos (10584)

### Jos (10584) (view profile)

function idx = sub2allind(sz, varargin)
tf = false(sz) ;
tf(varargin{:}) = true ;
idx = find(tf) ;

 7 Feb 2012 1.5 Added H1 line; fixed bug when asking for a column of indices only 6 Sep 2011 1.4 * shape of output fits the adressed field now * little more docu and error checking 28 Jan 2011 1.1 * Implemented colon operator (Thanks to Matt J) * possible errors catched; more comments
##### MATLAB Release
MATLAB 7.12 (R2011a)