I am doing my work on archeology domain, I am trying to generate all the sequence of a given variable with some precedence constraint. For example, if we have five object 1 2 3 4 5 , then there are 5! ways but if we impose some precedence constraints like:
The sequence should always start from 1.
After 1 only 2 or 3 can be attached.
4 can come after 5 or 3
5 can come after 4 or 2
at last I should get answer like given below
1 2 3 5 4; 1 2 3 4 5; 1 2 5 4 3; 1 2 5 3 4;
1 3 4 5 2; 1 3 4 2 5; 1 3 2 5 4; 1 3 2 4 5;
I tried different function like allcomb, ndgrid, treenode, perms, and matrix fuction but I can't able to impose the precedence constraints. And also I am using MATLAB for first time but i searched all question and answer but haven't found the one I am looking for.
I found some answer without OR constraints but in my problem i have to use OR.
I suggest generating all possible combinations of 1 to 5, and remove the invalid ones.
Code example:
%generates all possible combinations from 1 to 5, where 1 is the first
%number
allCombs = perms(2:5);
allCombs = [ones(size(allCombs,1),1),allCombs];
%calclates rows in which the constraints for 1,4,5 holds
constraintsFor1 = union(findKAfterNRows(allCombs,2,1),findKAfterNRows(allCombs,3,1));
constraintsFor4 = union(findKAfterNRows( allCombs, 4,5 ),findKAfterNRows( allCombs, 4,3 ));
constraintsFor5 = union(findKAfterNRows( allCombs, 5,2 ),findKAfterNRows( allCombs, 5,4 ));
%calculates the valid rows
resultRows = intersect(constraintsFor1,constraintsFor4);
resultRows = intersect(resultRows,constraintsFor5);
%generates final output
outputMask = allCombs(resultRows,:);
Where findKAfterNRows is a function which receive a matrix of combinations, and two numbers - k and n, and returns rows in which k comes after n:
function [ validRows ] = findKAfterNRows( mat, k,n )
kMask = single(mat==k);
nMask = single(mat==n);
n = size(mat,2);
kernel = zeros(1,n);
kernel(1:floor(n/2)) = 1;
kMaskShiftLeft = conv2(kMask,kernel,'same');
validRows = find(sum(nMask==1 & kMaskShiftLeft==1,2)==1);
end
Results:
outputMask =
1 3 4 2 5
1 3 4 5 2
1 3 2 4 5
1 3 2 5 4
1 2 3 4 5
1 2 3 5 4
1 2 5 4 3
1 2 5 3 4
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
Given any number. Lets say for example 5, I need to generate a matrix similar to this:
1 2 3 4 5
2 2 3 4 5
3 3 3 4 5
4 4 4 4 5
5 5 5 5 5
How to generate a matrix similar to this using Matlab?
I'd use bsxfun:
n = 5;
matrix = bsxfun(#max, 1:n, (1:n).');
An alternative (probably slower) is to use ndgrid:
n = 5;
[ii, jj] = ndgrid(1:n);
matrix = max(ii, jj);
Nothing will ever beat bsxfun as used by Luis Mendo., but for the sake of reminding people of the existence of Matlab's gallery function, here another approach:
n = 5;
A = gallery('minij',n)
B = n + 1 - A(end:-1:1,end:-1:1)
A =
1 1 1 1 1
1 2 2 2 2
1 2 3 3 3
1 2 3 4 4
1 2 3 4 5
B =
1 2 3 4 5
2 2 3 4 5
3 3 3 4 5
4 4 4 4 5
5 5 5 5 5
This question already has answers here:
Generate all possible combinations of the elements of some vectors (Cartesian product)
(4 answers)
Closed 8 years ago.
So I'm writing a program to determine the unique combinations of a beaded necklace, but I can't seem to get it right. The rules are you can't have the same necklace forwards and backwards, and you can't have the same necklace with one bead being slid around to the other end. I've attached some pictures to clarify.
I wrote the code for it, and I thought I had achieved what I was trying to do, but it's not working correctly.
n = [1 2 3 4 2 4];
% green = 1
% blue = 2
% yellow = 3
% red = 4
p = perms(n);
total = max(size(p));
for i = 1:max(size(p))
q = p;
q(i) = [];
for j = 1:max(size(q))
if isequal(p(i),fliplr(q(j)))
total = total - 1;
elseif isequal(p(i),circshift(q(j),[1,1]))
total = total - 1;
elseif isequal(p(i),circshift(q(j),[length(q(j))-1,length(q(j))-1]))
total = total - 1;
end
disp(total)
end
end
Logically, this makes sense to me, but I could just be crazy.
If the problem size is small, you can vectorize all the comparisons (using bsxfun):
n = [1 2 3 4 2 4];
%// green = 1
%// blue = 2
%// yellow = 3
%// red = 4
N = numel(n);
p = perms(n).'; %'// generate all permutations
p2 = NaN([size(p) N+1]); %// this will store permutations with flips and shifts
p2(:,:,1) = p; %// original
p2(:,:,2) = flipud(p); %// flips
for k = 1:N-1
p2(:,:,2+k) = circshift(p,k); %// circular shifts
end
eqElem = bsxfun(#eq, p, permute(p2, [1 4 2 3]));
eqMat = squeeze(any(all(eqElem, 1), 4)); %// 1 if equal
remove = any(tril(eqMat, -1), 1); %// remove permutations that are "similar"
%// to a previous one, where "similar" means "equal up to circular shifts or
%// flips"
result = p(:,~remove).'; %'// all valid arrangements; one per row
resultNum = size(result, 1); %// number of arrangements
Results:
result =
1 3 2 2 4 4
1 3 2 4 4 2
1 3 2 4 2 4
1 3 4 2 2 4
1 3 4 2 4 2
1 3 4 4 2 2
1 2 3 2 4 4
1 2 3 4 2 4
1 2 3 4 4 2
1 2 2 3 4 4
1 2 2 4 4 3
1 2 2 4 3 4
1 2 4 3 2 4
1 2 4 3 4 2
1 2 4 2 3 4
1 2 4 2 4 3
1 2 4 4 2 3
1 2 4 4 3 2
1 4 4 3 2 2
1 4 4 2 2 3
1 4 4 2 3 2
1 4 3 4 2 2
1 4 3 2 2 4
1 4 3 2 4 2
1 4 2 3 2 4
1 4 2 3 4 2
1 4 2 2 3 4
1 4 2 2 4 3
1 4 2 4 2 3
1 4 2 4 3 2
resultNum =
30
You should do p = unique(p,'rows') before any loops. To see why, call perms([1 1 1]) at the command line.
There are a few issues here:
1) p, the perms, is a 2D matrix, so to get each perm you need to do p(i,:) to get the row. p(i) is just a single number.
2) You don't remove wrong answers from your list, so you will check against them twice. For example, say the first in the list is [1 2 3 4 2 4]; and the second is [4 2 4 3 2 1];. The fliplr check will compare these two combinations twice, once in the first loop around, once in the second.
3) If you want to make sure that any permutation which is a rotation is excluded (not just moving one bead around), you'll need some more circshift.
Consider using ismember with rows option again to compare a single row (e.g. a flipped version of the row you're checking) to an entire matrix.
I am trying to flip certain parts of a matrix. I can explain better by example. Let's say that I have a matrix
M = [ 1 3 6;
1 2 4;
1 7 1;
2 9 0;
2 8 3;
2 4 2;
2 3 1;
3 6 5;
3 4 5;
3 1 9;
4 2 4;
4 8 6 ]
What I'd like to do here is take any rows with an even number in the first column, and flip the third column elements. The end result would look like this:
1 3 6
1 2 4
1 7 1
2 9 1 *
2 8 2 *
2 4 3 *
2 3 0 *
3 6 5
3 4 5
3 1 9
4 2 6 *
4 8 4 *
Note the rows marked with a star have had the elements of the third column flipped upside-down. The problem I'm having is going through each row like in a for-loop you cannot flip an entire set of rows.
Thanks in advance for any help.
Another time accumarray is the way to go:
A =[ 1 3 6 ;
1 2 4 ;
1 7 1 ;
2 9 0 ;
2 8 3 ;
2 4 2 ;
2 3 1 ;
3 6 5 ;
3 4 5 ;
3 1 9 ;
4 2 4 ;
4 8 6 ]
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} ); %// get groups according to
%// first column and flip it
C = vertcat(C{:}); %// cell array returned,
%// transform to matrix
mask = ~mod(A(:,1),2); %// mask for even numbers
A(mask,3) = C(mask); %// replace masked values of 3rd column with flipped ones
returns:
A =
1 3 6
1 2 4
1 7 1
2 9 1
2 8 2
2 4 3
2 3 0
3 6 5
3 4 5
3 1 9
4 2 6
4 8 4
Certainly slower, but just for fun in two lines:
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} );
A(~mod(A(:,1),2),3) = getfield( vertcat(C{:}), {~mod(A(:,1),2)});
%// well no, I won't explain it...
Edit: I assumed your first column just contains integers!
I would suggest you break the problem down into stages, something like so:
Identify blocks you wish to flip
Extract them
Flip them
Replace them
You can identify a set of even numbers using the unique and mod functions, then use a for loop over them and use logical indexing to pull/replace the blocks.
Here, try this
a = magic(5); % Some data in a 5x5 matrix
b = 1:numel(a); % Indices of <a>
Rearrange b however you want, then do a=a(b) to reassign a based on the reassigned indices of b. For example, the following code
disp(a(b));
would just return the elements of a in their original order. For your application this code should work:
a = <your matrix data>
b = 1:numel(a);
b = [b(1:27) fliplr(b(28:31)) b(32:34) fliplr(b(35:36))] % Change this part
a = reshape(a(b),size(a))
You should change b based on whatever you need it to do.
I want to create a table which contains all possible combinations, order is important, of N numbers in sets of k using matlab.
I tried Combinations = combntns(set,subset) and Combinations = perms(v) and Combinations = combnk(v,k)but in those order is not important.
An example:
nchoosek(1:5,3)
ans =
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
While it should also include
1 3 2
1 4 2
1 5 2
1 3 5
1 5 3
...
The number of possible combinations is given by the following by the function:
N!/(N-k)!
source: Mathisfun.com
Is there a possible way to do it this using matlab functions?
Try this memory efficient solution:
n = 5; k = 3;
nk = nchoosek(1:n,k);
p=zeros(0,k);
for i=1:size(nk,1),
pi = perms(nk(i,:));
p = unique([p; pi],'rows');
end
p should contain what you are describing. At least size(p,1) == factorial(n)/factorial(n-k) or 60 for this example.