Reputation: 157
I have written this code:
a = repelem(ones(7,8)-2.*eye(7,8), 7:-1:1, 1);
for i=1:7
a(i,i+1)=-1;
end
for i=8:13
a(i,i-5)=-1;
end
for i=14:18
a(i,i-10)=-1;
end
for i=19:22
a(i,i-14)=-1;
end
for i=23:25
a(i,i-17)=-1;
end
for i=26:27
a(i,i-19)=-1;
end
for i=28:28
a(i,i-20)=-1;
end
To produce this matrix:
-1 -1 1 1 1 1 1 1
-1 1 -1 1 1 1 1 1
-1 1 1 -1 1 1 1 1
-1 1 1 1 -1 1 1 1
-1 1 1 1 1 -1 1 1
-1 1 1 1 1 1 -1 1
-1 1 1 1 1 1 1 -1
1 -1 -1 1 1 1 1 1
1 -1 1 -1 1 1 1 1
1 -1 1 1 -1 1 1 1
1 -1 1 1 1 -1 1 1
1 -1 1 1 1 1 -1 1
1 -1 1 1 1 1 1 -1
1 1 -1 -1 1 1 1 1
1 1 -1 1 -1 1 1 1
1 1 -1 1 1 -1 1 1
1 1 -1 1 1 1 -1 1
1 1 -1 1 1 1 1 -1
1 1 1 -1 -1 1 1 1
1 1 1 -1 1 -1 1 1
1 1 1 -1 1 1 -1 1
1 1 1 -1 1 1 1 -1
1 1 1 1 -1 -1 1 1
1 1 1 1 -1 1 -1 1
1 1 1 1 -1 1 1 -1
1 1 1 1 1 -1 -1 1
1 1 1 1 1 -1 1 -1
1 1 1 1 1 1 -1 -1
I'm looking for a more efficient way to produce this matrix. One way to do so is:
S=[-1 -1 1 1 1 1 1 1];
P=unique(perms(S),'rows');
But I don't want to use permutation at all because I want to use this code and make matrices with bigger dimensions and using permutation makes it impossible.
Upvotes: 2
Views: 67
Reputation: 7597
The answer by @gnovice is excellent, however I'd like to add an alternative answer for pedagogical purposes. As gnovice states "You're producing every permutation of positioning 2 values of -1 in a 1-by-8 vector of ones". We can apply this to our problem by thinking about how we can generate successive permutations of [-1 -1 1 1 1 1 1 1]
.
Coming from C++
, this is very intuitive as the algorithm
library offers std::next_permutation
which generates the next lexicographical permutation of your vector. The algorithm is quite simple and can be found here: https://en.cppreference.com/w/cpp/algorithm/next_permutation. In fact, a much more generalized version of this algorithm has been implemented in matlab
by Jos. We will utilize nextperm_local
that can be found at the very bottom of the "Functions" tab on the file exchange page for nextperm.
myP = [-1 -1 1 1 1 1 1 1];
function P = nextperm_local(P)
k1 = find(P(2:end) > P(1:end-1), 1, 'last');
if isempty(k1)
k1 = 0;
else
k2 = find(P(k1)<P, 1, 'last');
P([k1 k2]) = P([k2 k1]);
end
P((k1+1):end) = P(end:-1:(k1+1));
end
total = nchoosek(8, 2);
output = zeros(total, 8);
for i = 1:total
output(i,:) = myP ;
myP = nextperm_local(myP) ;
end
And produces the following matrix:
output =
-1 -1 1 1 1 1 1 1
-1 1 -1 1 1 1 1 1
-1 1 1 -1 1 1 1 1
-1 1 1 1 -1 1 1 1
-1 1 1 1 1 -1 1 1
-1 1 1 1 1 1 -1 1
-1 1 1 1 1 1 1 -1
1 -1 -1 1 1 1 1 1
1 -1 1 -1 1 1 1 1
1 -1 1 1 -1 1 1 1
1 -1 1 1 1 -1 1 1
1 -1 1 1 1 1 -1 1
1 -1 1 1 1 1 1 -1
1 1 -1 -1 1 1 1 1
1 1 -1 1 -1 1 1 1
1 1 -1 1 1 -1 1 1
1 1 -1 1 1 1 -1 1
1 1 -1 1 1 1 1 -1
1 1 1 -1 -1 1 1 1
1 1 1 -1 1 -1 1 1
1 1 1 -1 1 1 -1 1
1 1 1 -1 1 1 1 -1
1 1 1 1 -1 -1 1 1
1 1 1 1 -1 1 -1 1
1 1 1 1 -1 1 1 -1
1 1 1 1 1 -1 -1 1
1 1 1 1 1 -1 1 -1
1 1 1 1 1 1 -1 -1
Upvotes: 2
Reputation: 125854
You're producing every permutation of positioning 2 values of -1
in a 1-by-8 vector of ones. Therefore, you can generate the column indices of the -1
values using nchoosek
, then modify the matrix a
in a single indexing step using sub2ind
:
indices = nchoosek(1:8, 2);
N = size(indices, 1);
a = ones(N, 8);
a(sub2ind([N 8], [1:N 1:N].', indices(:))) = -1;
And the output:
a =
-1 -1 1 1 1 1 1 1
-1 1 -1 1 1 1 1 1
-1 1 1 -1 1 1 1 1
-1 1 1 1 -1 1 1 1
-1 1 1 1 1 -1 1 1
-1 1 1 1 1 1 -1 1
-1 1 1 1 1 1 1 -1
1 -1 -1 1 1 1 1 1
1 -1 1 -1 1 1 1 1
1 -1 1 1 -1 1 1 1
1 -1 1 1 1 -1 1 1
1 -1 1 1 1 1 -1 1
1 -1 1 1 1 1 1 -1
1 1 -1 -1 1 1 1 1
1 1 -1 1 -1 1 1 1
1 1 -1 1 1 -1 1 1
1 1 -1 1 1 1 -1 1
1 1 -1 1 1 1 1 -1
1 1 1 -1 -1 1 1 1
1 1 1 -1 1 -1 1 1
1 1 1 -1 1 1 -1 1
1 1 1 -1 1 1 1 -1
1 1 1 1 -1 -1 1 1
1 1 1 1 -1 1 -1 1
1 1 1 1 -1 1 1 -1
1 1 1 1 1 -1 -1 1
1 1 1 1 1 -1 1 -1
1 1 1 1 1 1 -1 -1
Upvotes: 2