1
votes

Indeed, my problem is a succession of my previous problem:

1) Extract submatrices, 2) vectorize and then 3) put back

Thanks to Dan and his ideas works perfectly for the purpose.


My new problem is this:

If I have a 3D matrix, 8 by 8 by 12, e.g. A = randn(8,8,12).

Let's see the linear index of the first slice:

enter image description here

From Dan's solution, I understand that A[4:6, 4:6, :] can extract the corresponding parts of all slices.

However, going back to my real situations, extracting parts by actually counting rows and columns seem not suit my purpose because my matrix size is huge and I do have many sub-matrices to be extracted.

So, I prefer to work on linear index and want to ask if there are any ways to work with this possibility.

Here is my trial:

By defining sub_group = [28 29 30 36 37 38 44 45 46], then A(sub_group) can extract sub-matrix from the first slice of the 3D matrix, A.

I understand that A(sub_group + 8*8*(n-1)) can extract the sub-matrix from the nth slice.

I aim to only work with my sub_group and then extract the same part of every slice.

Most importantly, I have to put back the sub-matrices after updating their values.

So, is there are any quick syntax for matlab to work for my purpose?

I appreciate for your help.

1

1 Answers

1
votes

Approach #1

For cases like this when you need to calculate linear indices, you can use bsxfun as shown here -

%// Store number of rows in A as a variable
M = size(A,1)

%// Get start and offset linear indices for the first slice and thus sub_group
start_idx = (colstart-1)*M + rowstart
offset_idx = bsxfun(@plus,[0:rowstop - rowstart]', [0:colstop-colstart]*M) %//'
sub_group = reshape(start_idx + offset_idx,1,[])

%// Calculate sub_groups for all 3D slices
all_sub_groups = bsxfun(@plus,sub_group',[0:size(A,3)-1]*numel(A(:,:,1)))

Sample run -

A(:,:,1) =
     0.096594      0.52368      0.76285      0.83984      0.27019
      0.84588      0.65035      0.57569      0.42683       0.4008
       0.9094      0.38515      0.63192      0.63162      0.55425
     0.011341       0.6493       0.2782      0.83347      0.44387
A(:,:,2) =
     0.090384     0.037262      0.38325      0.89456      0.89451
      0.74438       0.9758      0.88445      0.39852      0.21417
     0.032615      0.52234      0.25502      0.62502    0.0038592
      0.42974      0.90963      0.90905       0.5676      0.88058
rowstart =
     2
rowstop =
     4
colstart =
     3
colstop =
     5
sub_group =
    10    11    12    14    15    16    18    19    20
all_sub_groups =
    10    30
    11    31
    12    32
    14    34
    15    35
    16    36
    18    38
    19    39
    20    40

Approach #2

For a quick syntax based solution, sub2ind could be suggested here. The implementation would look something like this -

[X,Y] = ndgrid(rowstart:rowstop,colstart:colstop);
sub_group = sub2ind(size(A(:,:,1)),X,Y);

[X,Y,Z] = ndgrid(rowstart:rowstop,colstart:colstop,1:size(A,3));
all_sub_groups = sub2ind(size(A),X,Y,Z);