'How to decompose a 9x9 matrix to 3x3 matrices?

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


Solution 1:[1]

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.

Solution 2:[2]

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

Solution 3:[3]

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.

Solution 4:[4]

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

Solution 5:[5]

#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     
========

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Wolfie
Solution 4 Adriaan
Solution 5 Andrei