'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 extendM
to larger sizes.Don't use
i
orj
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 superfluousInitialise
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
andm
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
andsize(M,2)/m
both need to be integers. If this is not the case, this code will error out on the initialisation ofv
.
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 |