4

I'm trying to decompose a 9x9 matrix into 9 3x3 matrices. I've already used the command reshape, but the matrices it returns are the ones as transforming the columns of the 9x9 matrix to 3x3 matrices, but that isn't what I need. This is 9x9 the matrix M

0   0   0   0   0   0   0   7   6
0   2   0   9   0   0   0   0   0
0   3   8   0   5   4   1   0   0
9   0   0   5   0   0   0   3   0
0   0   0   0   1   8   0   6   7
4   0   0   0   0   0   2   0   0
0   1   0   8   0   0   0   5   0
0   0   0   0   0   7   0   0   0
6   0   2   0   3   0   8   9   4

And I need it in form

0 0 0    0 0 0    0 7 6
0 2 0    9 0 0    0 0 0
0 3 8    0 5 4    1 0 0       etc...

This code generates the matrices exactly as I need them, but only saving the last one:

for i=[1 4 7]
    for j=[1 4 7]
        v(:,:)=M([i:i+2],[j:j+2])
    end
end
Adriaan
  • 17,741
  • 7
  • 42
  • 75
David BG
  • 41
  • 3

5 Answers5

5

You make a new v of size 3x3 every loop iteration, i.e. you overwrite it. What you can easily do is to add a third dimension, and store all your separate matrices along there:

n = 3;  % Amount of rows of the sub-matrices
m = 3;  % Amount of columns of the sub-matrices
v = zeros(size(M,1)./n,size(M,2)./m,(size(M,1)*size(M,2))./(n*m)); % Initialise v

kk = 1;  % Initialise page counter
for ii = 1:n:size(M,1)
    for jj = 1:m:size(M,2)
        v(:,:,kk) = M(ii:ii+2, jj:jj+2); % Save on page kk
        kk = kk+1;  % Increase page counter
    end
end

A few other notes:

  • In order to generalise the code I used size(M) everywhere, such that you can easily extend M to larger sizes.

  • Don't use i or j as indices/variables names, as they denote the imaginary unit. Using those can easily lead to hard to debug errors.

  • ii:ii+2 already is an array, adding square brackets is superfluous

  • Initialise v, i.e. tell MATLAB how large it will be before going into the loop. Otherwise, MATLAB will have to increase its size every iteration,which is very slow. This is called preallocation.

  • n and m obviously need to be integers, but not only that. You need an integer amount of sub-matrices to fill each dimension, i.e. size(M,1)/n and size(M,2)/m both need to be integers. If this is not the case, this code will error out on the initialisation of v.

Adriaan
  • 17,741
  • 7
  • 42
  • 75
  • Thanks, it was really helpful. I had to make two little corrections. I initialised the counter kk from zero, so the first matrix was v(:,:,1) and removed the line v=zeros(size...), because it generates extra empty matrices. But it worked perfectly :) – David BG Aug 19 '20 at 05:33
  • @DavidBG I don't get it; setting `kk=0` would result in the first matrix being put in `v(:,:,0)`, which doesn't exist and will result in an error? Also, don't remove the preallocation, see my last bullet point, rather decrease the number of matrices to be generated. Probably the initialisation needed to be divided by 9 rather than 3, apologies, I updated. – Adriaan Aug 19 '20 at 05:42
  • Yeah, I'm sorry too. Since I use to use python, I deal with matrices initialising the counter from zero and in this case I relocated `kk=kk+1` before `v(:,:,kk)=M...` – David BG Aug 19 '20 at 21:56
3

You can also use mat2cell function. You need to declare the input_size and the chunk_size. Then you need to declare the number of chunks in each dimension (sc variable).

For example:

M = [0   0   0   0   0   0   0   7   6
     0   2   0   9   0   0   0   0   0
     0   3   8   0   5   4   1   0   0
     9   0   0   5   0   0   0   3   0
     0   0   0   0   1   8   0   6   7
     4   0   0   0   0   0   2   0   0
     0   1   0   8   0   0   0   5   0
     0   0   0   0   0   7   0   0   0
     6   0   2   0   3   0   8   9   4];

% Z = zeros(size(M, 1), size(M, 2));
input_size = size(M);
chunk_size = [3 3];
sc = input_size ./ chunk_size;

C = mat2cell(M, chunk_size(1)*ones(sc(1), 1),...
                chunk_size(2)*ones(sc(2), 1));
celldisp(C')

Output:

 
ans{1,1} =
 
     0     0     0
     0     2     0
     0     3     8

 
 
ans{2,1} =
 
     0     0     0
     9     0     0
     0     5     4

 
 
ans{3,1} =
 
     0     7     6
     0     0     0
     1     0     0

 
 
ans{1,2} =
 
     9     0     0
     0     0     0
     4     0     0

 
 
ans{2,2} =
 
     5     0     0
     0     1     8
     0     0     0

 
 
ans{3,2} =
 
     0     3     0
     0     6     7
     2     0     0

 
 
ans{1,3} =
 
     0     1     0
     0     0     0
     6     0     2

 
 
ans{2,3} =
 
     8     0     0
     0     0     7
     0     3     0

 
 
ans{3,3} =
 
     0     5     0
     0     0     0
     8     9     4
Ahmet
  • 7,527
  • 3
  • 23
  • 47
1

Using only linear indexing and implicit expansion:

%   Random example matrix
M   = randi(9,[9,12])

%   Block size
n   = 3;

%   Indexing
s   = size(M,1)
ind = [1:n].'+[0:n-1]*s+reshape(floor((0:n:(numel(M)/n)-1)/s)*n*s+mod(1:n:numel(M)/n,s)-1,1,1,[])

%   Split each block into a third dimension.
B   = M(ind)

Where:

[1:n].'+[0:n-1]*s =

     1   10   19
     2   11   20
     3   12   21

% The linear index of the first block

And:

reshape(floor((0:n:(numel(M)/n)-1)/s)*n*s+mod(1:n:numel(M)/n,s)-1,1,1,[]) = 

    ans(:,:,1) = 0
    ans(:,:,2) = 3
    ans(:,:,3) = 6
    ans(:,:,4) = 27
    ans(:,:,5) = 30
    ans(:,:,6) = 33
    ans(:,:,7) = 54
    ...

% The shifting number for each block

Noticed that the length of each dimension of the matrix M has to be divisible by n

Adriaan
  • 17,741
  • 7
  • 42
  • 75
obchardon
  • 10,614
  • 1
  • 17
  • 33
1

You can create a tiled index matrix, then use this to get the 3*3 arrays

idx = repelem( reshape(1:9,3,3), 3, 3 );
out = arrayfun( @(x) reshape(A(idx==x),3,3), 1:9, 'uni', 0 );

Explanation:

idx is a tiled array as shown:

idx = 
     1     1     1     4     4     4     7     7     7
     1     1     1     4     4     4     7     7     7
     1     1     1     4     4     4     7     7     7
     2     2     2     5     5     5     8     8     8
     2     2     2     5     5     5     8     8     8
     2     2     2     5     5     5     8     8     8
     3     3     3     6     6     6     9     9     9
     3     3     3     6     6     6     9     9     9
     3     3     3     6     6     6     9     9     9

Then the arrayfun line loops through the values 1 .. 9, and extracts the matrix where idx matches the indexing value of the loop. We have to use a final reshape here because the logical index turns the array 1D.

The output is a 9 by 1 cell array, where each cell is a submatrix.

Wolfie
  • 27,562
  • 7
  • 28
  • 55
-1

#java

// method decompose a 9*9 matrix to 3*3 matrices
public static int[][][] decompose(int[][] matrix) {
    int[][][] result = new int[9][3][3];

    for (int i = 0; i < 9; ) {
        for (int j = 0; j < 9; j += 3) {

            for (int k = 0; k < 9; k += 3) {
                for (int l = j; l < j + 3; l++) {
                    for (int m = k; m < k + 3; m++) {
                        result[i][l % 3][m % 3] = (matrix[l][m]);
                    }
                }
                i++;
            }
        }
    }
    return result;
}

For example:

        int[][] matrix = {
                {1, 2, 3, 10, 11, 12, 19, 20, 21},
                {4, 5, 6, 13, 14, 15, 22, 23, 24},
                {7, 8, 9, 16, 17, 18, 25, 26, 27},
                {28, 29, 30, 37, 38, 39, 46, 47, 48},
                {31, 32, 33, 40, 41, 42, 49, 50, 51},
                {34, 35, 36, 43, 44, 45, 52, 53, 54},
                {55, 56, 57, 64, 65, 66, 73, 74, 75},
                {58, 59, 60, 67, 68, 69, 76, 77, 78},
                {61, 62, 63, 70, 71, 72, 79, 80, 81}
        };
        int[][][] test = decompose(matrix);
        for (int[][] grid : test) {
            for (int[] gridLine : grid) {
                for (int i = 0; i < 3; i++) {
                    System.out.print(gridLine[i] + " ");
                }
                System.out.println();
            }
            System.out.println("========");
        }

Output:

1 2 3     
4 5 6     
7 8 9     
========
10 11 12     
13 14 15     
16 17 18     
========
19 20 21     
22 23 24     
25 26 27     
========
28 29 30     
31 32 33     
34 35 36     
========
37 38 39     
40 41 42     
43 44 45     
========
46 47 48     
49 50 51     
52 53 54     
========
55 56 57     
58 59 60     
61 62 63     
========
64 65 66     
67 68 69     
70 71 72     
========
73 74 75     
76 77 78     
79 80 81     
========
Andrei
  • 1