Reputation: 3075
I want to create a matrix A [4x8] as follows.
The matrix A always has 1
as its diagonal. A11,A22,A33,A44 = 1
This matrix can be considered as two halves with first half being the first 4 columns and the second half being the second 4 columns like something below :
1 -1 -1 -1 1 0 0 1
A = -1 1 -1 0 0 1 0 0
-1 -1 1 0 1 0 0 0
-1 -1 -1 1 1 1 0 0
Each row in the first half can have either two or three -1's:
-1
's then that corresponding row in the second half should have one 1
-1
's the second half of the matrix should have two 1
's.The overall objective is to have the sum of each row to be 0
. I need to generate all possible combinations of a matrix like this.
It will be better if the matrix with new combination be created at each iteration so that after using it I can discard it or else storing all the combinations is very space intensive. Can anybody help me ?
one possible solution I could think of is to generate all possible combinations of row1, row2, row3 and row4 and create a matrix in each iteration. Does that look feasible?
Upvotes: 2
Views: 2688
Reputation: 125854
Here's one possible solution. If you ignore the diagonal ones for the moment, you can generate all possible patterns for the other 7 values using the functions KRON, REPMAT, PERMS, UNIQUE, EYE, and ONES:
>> rowPatterns = [kron(eye(3)-1,ones(4,1)) ... %# For 2 out of 3 as -1
repmat(eye(4),3,1); ... %# For 1 out of 4 as 1
repmat([-1 -1 -1],6,1) ... %# For 3 out of 3 as -1
unique(perms([1 1 0 0]),'rows')] %# For 2 out of 4 as 1
rowPatterns =
0 -1 -1 1 0 0 0
0 -1 -1 0 1 0 0
0 -1 -1 0 0 1 0
0 -1 -1 0 0 0 1
-1 0 -1 1 0 0 0
-1 0 -1 0 1 0 0
-1 0 -1 0 0 1 0
-1 0 -1 0 0 0 1
-1 -1 0 1 0 0 0
-1 -1 0 0 1 0 0
-1 -1 0 0 0 1 0
-1 -1 0 0 0 0 1
-1 -1 -1 0 0 1 1
-1 -1 -1 0 1 0 1
-1 -1 -1 0 1 1 0
-1 -1 -1 1 0 0 1
-1 -1 -1 1 0 1 0
-1 -1 -1 1 1 0 0
Note that this is 18 possible patterns for any given row, so your matrix A
can have 18^4 = 104,976 possible row patterns (quite a bit). You can generate every possible 4-wise row pattern index by using the functions NDGRID, CAT, and RESHAPE:
[indexSets{1:4}] = ndgrid(1:18);
indexSets = reshape(cat(5,indexSets{:}),[],4);
And indexSets
will be a 104,976-by-4 matrix with each row containing one combination of 4 values between 1 and 18, inclusive, to be used as indices into rowPatterns
to generate a unique matrix A
. Now you can loop over each set of 4-wise row pattern indices and generate the matrix A
using the functions TRIL, TRIU, EYE, and ZEROS:
for iPattern = 1:104976
A = rowPatterns(indexSets(iPattern,:),:); %# Get the selected row patterns
A = [tril(A,-1) zeros(4,1)] + ... %# Separate the 7-by-4 matrix into
[zeros(4,1) triu(A)] + ... %# lower and upper parts so you
[eye(4) zeros(4)]; %# can insert the diagonal ones
%# Store A in a variable or perform some computation with it here
end
Upvotes: 5
Reputation: 124563
Here is another solution (with minimal looping):
%# generate all possible variation of first/second halves
z = -[0 1 1; 1 0 1; 1 1 0; 1 1 1]; n = -sum(z,2);
h1 = {
[ ones(4,1) z(:,1:3)] ;
[z(:,1:1) ones(4,1) z(:,2:3)] ;
[z(:,1:2) ones(4,1) z(:,3:3)] ;
[z(:,1:3) ones(4,1) ] ;
};
h2 = arrayfun(@(i) unique(perms([zeros(1,4-i) ones(1,i)]),'rows'), (1:2)', ...
'UniformOutput',false);
%'# generate all possible variations of complete rows
rows = cell(4,1);
for r=1:4
rows{r} = cell2mat( arrayfun( ...
@(i) [ repmat(h1{r}(i,:),size(h2{n(i)-1},1),1) h2{n(i)-1} ], ...
(1:size(h1{r},1))', 'UniformOutput',false) );
end
%'# generate all possible matrices (pick one row from each to form the matrix)
sz = cellfun(@(M)1:size(M,1), rows, 'UniformOutput',false);
[X1 X2 X3 X4] = ndgrid(sz{:});
matrices = cat(3, ...
rows{1}(X1(:),:), ...
rows{2}(X2(:),:), ...
rows{3}(X3(:),:), ...
rows{4}(X4(:),:) );
matrices = permute(matrices, [3 2 1]); %# 4-by-8-by-104976
%#clear X1 X2 X3 X4 rows h1 h2 sz z n r
Next you can access the 4-by-8 matrices as:
>> matrices(:,:,500)
ans =
1 -1 -1 -1 0 1 0 1
-1 1 -1 0 0 0 1 0
0 -1 1 -1 0 0 1 0
0 -1 -1 1 0 0 0 1
We could also confirm that all rows in all matrices sum to zero:
>> all(all( sum(matrices,2)==0 ))
ans =
1
Upvotes: 2