6

I'm trying to access a part of a multidimensional array in Matlab - it could be done like this: X(2:3, 1:20, 5, 4:7) However, neither the number of elements, nor the ranges are fixed, so I want to provide the indices from arrays - for the above example they'd be

ind1 = [2 1 5 4];
ind2 = [3 20 5 7];

For a fixed number of dimensions this is not a problem (X(ind1(1):ind2(1),...), but since they are not I'm not sure how to implement this in Matlab. Is there a way? Or should I approach this differently?

Jabor
  • 95
  • 1
  • 5
  • 1
    I'm a little confused. Are you saying that the dimensions can change from 3D to 5D etc? And how do you know which indices you want? – Flynn Jul 19 '17 at 18:16
  • The dimensions do not change: If u was a 5x7x8x9 array and `v=u(2:3,6:7,6:6,3:9)` then v would still be 4D - however `v(1,1,1,1)=u(2,6,6,3)`. The accessing is not a problem, giving the array the arguments is. – Jabor Jul 19 '17 at 18:21
  • I'm still trying to figure out your question/problem. Do you want v(1,1,1,1) to be v(2,6,6,3) instead? Or you just want a better way to access X(ind1(1):ind2(1)...) . Or you don't want to create a manual input of ind1 = ... and ind2 = ... ? – Flynn Jul 19 '17 at 18:33
  • Basically you a 4D matrix/tensor with unknown dimensions and you want to extract 4D sub-matrix/tensor based on indices `ind1` and `ind2`? So why wouldn't `v = X(ind1(1):ind2(1), ind1(2):ind2(2), ind1(3):ind2(3), ind1(4):ind2(4));` work as you will always 4D? – mpaskov Jul 19 '17 at 18:36
  • @mpaskov - I am not always 4 dimensional; therefore I cannot "hardcode" it as X(ind1(1):ind2(1), ... ind1(4):ind2(4)) because I do not know how many arguments I have. – Jabor Jul 19 '17 at 18:45
  • @Flynn - I have the arrays ind1 and ind2. I want to use a part of the multidimensional array (u the whole one, v the part as above) as input for another function. Since the dimension varies I'm wondering how to access such a part. – Jabor Jul 19 '17 at 18:45
  • @Jabor You replied above "The dimensions do not change". And now you're saying "It's now always 4 dimensional" ... It's hard to answer this question when it isn't clear. Sorry! – Flynn Jul 19 '17 at 18:47
  • @Flynn - Maybe I was unclear above. I'm trying to work with one tensor (=multiarray) at a time. Of this tensor the dimensions are fixed. However, the code needs to work with tensors of arbitrary dimension, therefore I cannot fix it on (e.g.) 4 dimensions. Edit to further clarify: With "dimension" I always mean the number number of indices, not the size of them by the way. So the 5x7x8x9 array above has dimension 4, not 5,7,8 and 9. – Jabor Jul 19 '17 at 18:49
  • So what you are actually saying is that you have a ND matrix and you extract ND sub-matrix. You do not know `N` in advance but you know that from the big matrix to the sub-matrix the number of dimensions are the same, `N`. – mpaskov Jul 19 '17 at 18:56
  • @mpaskv - correct – Jabor Jul 19 '17 at 18:58

2 Answers2

6

Using comma separated lists you can make it a more quick and friendly:

% some test data
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
X = randi(99,20,20,20,20);

% get all subscripts in column format
vecs = arrayfun(@colon,ind1,ind2,'un',0);
% extract the values
result = X(vecs{:});
EBH
  • 10,350
  • 3
  • 34
  • 59
  • I commented above about problems with the size of the subs matrix - while this solution is excellent for small cases, do you know a way to do this without saving every index? – Jabor Jul 19 '17 at 21:17
  • 1
    @Jabor See my edit for a simpler and quicker version. – EBH Jul 19 '17 at 21:27
4

There probably is a more elegant way, but this is a difficult problem so here is one solution:

% some test data
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
X = randi(99,20,20,20,20);

% get all subscripts in column format
vecs = arrayfun(@colon,ind1,ind2,'Uniformoutput',false);
subs = combvec(vecs{:}).';
% manual sub2ind for a matrix where each row contains one subscript
sizeX = size(X);
idx = cumprod([1 sizeX(1:end-1)])*(subs - [zeros(size(subs,1),1) ones(size(subs,1),size(subs,2)-1)]).';
% reshape
result = reshape(X(idx),ind2-ind1+1);

Subscripts to indices conversion based on Gnovices answer in Indexing of unknown dimensional matrix

Leander Moesinger
  • 2,449
  • 15
  • 28
  • This is one of my first times working in Matlab, but I think I understood your method; thanks a lot for it. I hope I'm not asking for too much, but looking at the subs matrix it will use (for d dimensions and a mode size of up to n; d=4 and n=20 in your example) n^d entries. This is a problem in my usecase as sizes for both in the thousands are not unusual. The tensor itself is saved in a smart way so it doesn't matter, but this matrix would be ridiculously gigantic. Is there a way to circumvent it's usage? – Jabor Jul 19 '17 at 21:10
  • Hm, i wouldn't know of any way. But the subs matrix should only be of size d x `prod(ind2-ind1+1)` if I'm not mistaken? So it increases only linearly both with length of ind1 and the number of elements you want to extract. – Leander Moesinger Jul 19 '17 at 21:18
  • Oh, you're correct of course. Still this sadly happens to be 8GB for `ind1 = [1 1 1 1 1 1 1]; ind2 = [15 15 15 15 15 15 15];` – Jabor Jul 19 '17 at 21:27