Consider a set,
S = {1,2,3,4,5,6,7}
I am trying to come up with a function which takes S as the input and gives me ALL possible arrays:
[ 1 ~ 2 ; 1 ~ 3 ; 1 ~ 4 ; 1 ~ 5 ; . . . ; 6 ~ 7 ]
[ 1 2 ~ 3 ; 1 2 ~ 4 ; ...; 2 3 ~ 1 ; 2 3 ~ 4....; 5 6 ~ 7]
.
.
.
[ 2 3 4 5 6 7 ~ 1 ; 1 3 4 5 6 7 ~ 2 ; ... ; 1 2 3 4 5 6 ~ 7 ]
Here notice that '~' is sort of like a delimiter placed in between the elements of k - combination such that the set appearing before the delimiter is always unique in each array.
For example, we want both 7-combinations
[ 2 3 4 5 6 7 ~ 1 ] and [ 1 2 3 4 5 6 ~ 7 ].
But we want only one of
[ 1 2 3 4 5 6 ~ 7 ] and [ 1 3 4 5 6 2 ~ 7 ].
My Code :
clear all
for k = 1:7
Set = nchoosek(1:7,k);
for i = 1:length(Set)
A = setdiff(1:7,Set(i,:));
P = nchoosek( A , 2 ); % trialing it for only A~B where B has only 2elements
L = length( P );
S = repmat( Set ( i,: ) , L,1);
for j = 1:L
S1(j,:) = setdiff( S(j,:) , P(j,:) );
W(j,:) = [ S1(j,:) , 0 , P(j,:) ];
end
W1(i,k) = {W};
end
end
This however produces an error at k=2.
Any ideas to make this work and efficiently.
I think I can outline how to achieve this.
to get the subset (for A) use setdiff
s = 1:7
b = 4
tmp = setdiff(s,b)
for the permutation use randperm
t2 = randperm(length(tmp))
A = tmp(t2)
for the specific subsets just pick the first n entries of A
Put the whole thing in some loops to create the set you describe.
Related
Suppose I have a list of length 2k, say {1,2,...,2k}. The number of possible ways of grouping the 2k numbers into k (unordered) pairs is n(k) = 1*3* ... *(2k-1). So for k=2, we have the following three different ways of forming 2 pairs
(1 2)(3 4)
(1 3)(2 4)
(1 4)(2 3)
How can I use Matlab to create the above list, i.e., create a matrix of n(k)*(2k) such that each row contains a different way of grouping the list of 2k numbers into k pairs.
clear
k = 3;
set = 1: 2*k;
p = perms(set); % get all possible permutations
% sort each two column
[~, col] = size(p);
for i = 1: 2: col
p(:, i:i+1) = sort(p(:,i:i+1), 2);
end
p = unique(p, 'rows'); % remove the same row
% sort each row
[row, col] = size(p);
for i = 1: row
temp = reshape(p(i,:), 2, col/2)';
temp = sortrows(temp, 1);
p(i,:) = reshape(temp', 1, col);
end
pairs = unique(p, 'rows'); % remove the same row
pairs =
1 2 3 4 5 6
1 2 3 5 4 6
1 2 3 6 4 5
1 3 2 4 5 6
1 3 2 5 4 6
1 3 2 6 4 5
1 4 2 3 5 6
1 4 2 5 3 6
1 4 2 6 3 5
1 5 2 3 4 6
1 5 2 4 3 6
1 5 2 6 3 4
1 6 2 3 4 5
1 6 2 4 3 5
1 6 2 5 3 4
As someone think my former answer is not useful, i post this.
I have the following brute force way of enumerating the pairs. Not particularly efficient. It can also cause memory problem when k>9. In that case, I can just enumerate but not create Z and store the result in it.
function Z = pair2(k)
count = [2*k-1:-2:3];
tcount = prod(count);
Z = zeros(tcount,2*k);
x = [ones(1,k-2) 0];
z = zeros(1,2*k);
for i=1:tcount
for j=k-1:-1:1
if x(j)<count(j)
x(j) = x(j)+1;
break
end
x(j) = 1;
end
y = [1:2*k];
for j=1:k-1
z(2*j-1) = y(1);
z(2*j) = y(x(j)+1);
y([1 x(j)+1]) = [];
end
z(2*k-1:2*k) = y;
Z(i,:) = z;
end
k = 3;
set = 1: 2*k;
combos = combntns(set, k);
[len, ~] = size(combos);
pairs = [combos(1:len/2,:) flip(combos(len/2+1:end,:))];
pairs =
1 2 3 4 5 6
1 2 4 3 5 6
1 2 5 3 4 6
1 2 6 3 4 5
1 3 4 2 5 6
1 3 5 2 4 6
1 3 6 2 4 5
1 4 5 2 3 6
1 4 6 2 3 5
1 5 6 2 3 4
You can also use nchoosek instead of combntns. See more at combntns or nchoosek
I have two values (k and j) which I know are within an nx3 matrix (M). I know that they're and on the same row and that j is always to the right of k, so if k is in M(2,1), then j will be in M(2,2). I tested for this earlier in the function, but now I want to know which row that is for a given k and j. I need the row number of their location to proceed. There are no duplicate combinations of k and j in the matrix.
So if I have the matrix
M=
1 4 5
1 5 7
k j 5
4 5 6
2 3 1
Then I want to know that they're in row 3. None of the columns are ordered.
What I have tried:
I used the code below
[row,~] = find(M==k);
I'm not sure how to look for a combination of them. I want to avoid using the find function. I hope to potentially use logical indexing.
How do I go about doing this? I hope this question makes sense.
You can use bsxfun -
find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
Being a relational operation with bsxfun, according to this post on benchmarked results, this should be pretty efficient.
Sample runs
Case #1 :
A =
1 4 5
1 5 7
6 7 1
4 5 6
2 3 1
k =
6
j =
7
>> find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
ans =
3
Case #2 :
A =
1 4 5
1 5 7
1 6 7
4 5 6
2 3 1
k =
6
j =
7
>> find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
ans =
3
Slightly different version on bsxfun. This one doesn't limit the matrix to three columns.
find(sum(((bsxfun(#eq,M,j) + bsxfun(#eq,M,k)) .* M).' ) == j+k >0)
Case 1:
M = [
1 4 5
1 5 7
6 7 1
4 5 6
2 3 1]
k=6;j=7;
ans = 3
Case 2:
M=[
1 4 5
1 5 7
1 6 7
4 5 6
2 3 1
];
k=6;j=7;
ans = 3
Use this:
row = find(((M(:,1) == k ) & ( M(:,2) == j)) | ((M(:,1) == k ) & ( M(:,3) == j)) | ((M(:,2) == k ) & ( M(:,3) == j)) )
Also, logical indexing can only give you a matrix with zeros at all other positions and one at your required position. But to get the index of that position, you will have to use find.
I have the following problem. Let's say I have four possible values {1 2 3 4} and I want a specific behavior of mod function
The behavior I seek is this one
1 mod 4 = 1
2 mod 4 = 2
3 mod 4 = 3
4 mod 4 = 4
but I have the following results with matlab.
1 mod 4 = 1
2 mod 4 = 2
3 mod 4 = 3
4 mod 4 = 0
Are there any ideas as how to achieve the desired behavior with the simplest way possible in MATLAB?
If A holds those values, you can subtract 1, perform mod and add back 1.
Sample run -
>> A = 1:8
A =
1 2 3 4 5 6 7 8
>> mod(A-1,4)+1
ans =
1 2 3 4 1 2 3 4
How about:
function [result] = my_mod(x,y)
m = mod(x,y);
result = m+~m*y;
The ~ negates the result from mod, i.e. :
~0 == 1
~1 == 0
~2 == 0
...
So we only add y if the result from mod is 0.
demo
>> my_mod(1:8, 4)
ans =
1 2 3 4 1 2 3 4
Consider the code :
clear all
N = 7;
Set = 1:N;
for i = 1:N-1
Set1 = nchoosek(Set,i);
[ L_Set1 , C_Set1] = size(Set1);
A = zeros( L_Set1,N-C_Set1);
ASS_R7 = zeros( L_Set1 , N+1 );
for i1 = 1:L_Set1
A(i1,:) = setdiff( 1:N , Set1(i1,:) );
ASS_R7(i1,:) = [ Set1(i1,:), 0 ,A(i1,:) ];
end
ASS_R(i) = {ASS_R7};
end
Here, ASS_R gives all the possible [ (N-k) 0 k ] sets where the elements are unique (and belong to [1,7].Also k>0).
I have been trying to generalize this code for all N<=7 and have not been able to come up with a solution.
To be more clear:
We get a cell array with cells of different sizes which look like this:
[ 1 2 3 4 5 6 0 7 ] . . . [ 1 0 2 3 4 5 6 7 ]
. .
{ . } . . . { . }
. .
[ 2 3 4 5 6 7 0 1 ] . . . [ 7 0 1 2 3 4 5 6 ]
However, I want all cells
[ 1 0 2 ] [ 1 0 2 3] [ 1 0 2 3 4 5 6 7 ]
. . .
{ . } . . { . } . . . { . }
. . .
[ 7 0 6 ] [ 7 0 6 5] [ 7 0 1 2 3 4 5 6 ]
[ 1 2 0 3 ] [ 1 2 0 3 4 5 6 7 ]
. .
{ . } . . . { . }
. .
[ 6 7 0 5 ] [ 6 7 0 1 2 3 4 5 ]
[ 1 2 3 4 5 6 0 7 ]
.
{ . }
.
[ 2 3 4 5 6 7 0 1 ]
Any ideas, guys?
Code
%%// Array of elements whose sets are to be formed
arr1 = 1:7;
%%// Get a size estimate of the final output cell array and initialize it
lim1 = cumsum(1:numel(arr1)-1);
outmat = cell(lim1(end),1);
%%// Get the cell array of sets, into outmat
cc1=1;
for k3 = 1:numel(arr1)-1
t1 = nchoosek(arr1,k3);
for k2=1:numel(arr1)-k3
mat1 =[];
for k1 = 1:size(t1,1)
t11 = t1(k1,:);
t2 = arr1(~ismember(arr1,t11));
t3 = nchoosek(t2,k2);
t4 = [repmat([t11 0],size(t3,1),1) t3];
mat1= [mat1; t4];
end
outmat(cc1)={mat1}; %%// Output
cc1 = cc1+1;
end
end
Suppose there are 2 vectors (i,j), A(10,1), B(10,1) which have obtain random values from [1,10] interval. eg.
A = [1 6 1 10 1 7 1 9 3 6]
B = [7 2 3 5 6 8 7 9 10 2].
I am interested in creating a new vector which will count how many values with the same i index occur. e.g.
1 and 7 ⇒ 2 occurrences
6 and 2 ⇒ 2 occurrences
1 and 3 ⇒ 1 occurrence
10 and 5 ⇒ 1 occurrence
1 and 6 ⇒ 1 occurrence
...
etc.
So that a final array/vector C occurs, with all the possible pairs and their counted occurrence with size C(number_of_pairs,2).
Use accumarray and then find:
A = [1 6 1 10 1 7 1 9 3 6];
B = [7 2 3 5 6 8 7 9 10 2]; %// data
aa = accumarray([A(:) B(:)], 1); %// how many times each pair occurs
[ii jj vv] = find(aa);
C = [ii jj vv]; %// only pairs which occurr at least once
In your example, this gives
C =
6 2 2
1 3 1
10 5 1
1 6 1
1 7 2
7 8 1
9 9 1
3 10 1
Or perhaps aa or vv are what you need; I'm not sure about what your desired output is.
Another possible approach, inspired by #Rody's answer:
mat = [A(:) B(:)];
[bb ii jj] = unique(mat, 'rows');
C = [mat(ii,:) accumarray(jj,1)];
Something like this?
A = [1 6 1 10 1 7 1 9 3 6];
B = [7 2 3 5 6 8 7 9 10 2];
%// Find the unique pairs
AB = [A;B].';
ABu = unique(AB, 'rows');
%// Count the number of occurrences of each unique pair
%// (pretty sure there's a better way to do this...)
C = arrayfun(#(ii) ...
[ABu(ii,:) sum(all(bsxfun(#eq, AB, ABu(ii,:)),2))], 1:size(ABu,1), ...
'UniformOutput', false);
C = cat(1,C{:});
Result:
C =
1 3 1
1 6 1
1 7 2
3 10 1
6 2 2
7 8 1
9 9 1
10 5 1
Something like this?
C = zeros(10);
for k = 1:10
C(A(k), B(k)) = C(A(k), B(k)) + 1
end