Code covered by the BSD License  

Highlights from
sub2allind

4.33333

4.3 | 3 ratings Rate this file 9 Downloads (last 30 days) File Size: 2.69 KB File ID: #30096
image thumbnail

sub2allind

by

 

19 Jan 2011 (Updated )

convert subscripts to ALL corresponding indices

| Watch this File

File Information
Description

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 );

Acknowledgements

This file inspired Catpad and N Dimensional Sparse Arrays.

MATLAB release MATLAB 7.12 (R2011a)
Tags for This File   Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (11)
20 Feb 2012 Alexander

Very useful, thanks)

26 Jul 2011 Marc  
29 Jan 2011 Matt J

"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.

29 Jan 2011 Michael Völker

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.

29 Jan 2011 Matt J

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).

28 Jan 2011 Michael Völker

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

28 Jan 2011 Michael Völker

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...

22 Jan 2011 Matt J

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 .

21 Jan 2011 Jos (10584)

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{:}) ;

20 Jan 2011 Michael Völker

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.

20 Jan 2011 Jos (10584)

What about the alternative code

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

Updates
28 Jan 2011

* Implemented colon operator (Thanks to Matt J)
* possible errors catched; more comments

06 Sep 2011

* shape of output fits the adressed field now
* little more docu and error checking

07 Feb 2012

Added H1 line; fixed bug when asking for a column of indices only

Contact us