How to do a permutation with restrictions? - matlab

I have a vector using Matlab whose values are from 1 to 18, I need to perform permutations of those values considering that certain numbers cannot go together. For example:
vector = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18]
In the conditions I have that the following numbers cannot go together:
1 and 7
1 and 8
1 and 17
1 and 18
2 and 6
2 and 7
2 and 8
2 and 17
2 and 18
So a valid permutation could be:
[1 2 4 3 5 6 7 8 9 10 11 12 13 14 15 17 16 18]
An invalid permutation could be:
[1 7 4 3 5 6 2 8 9 10 11 12 13 14 15 17 16 18] 1 and 7 together
[1 8 4 3 5 6 2 7 9 10 11 12 13 14 15 17 16 18] 1 and 8 together
[1 17 4 3 5 6 2 8 9 10 11 12 13 14 15 7 16 18] 1 and 17 together
These conditions must apply in any position of the vector.
I have no ideas how to do this, if someone could give me ideas I would really appreciate it.

Taking into account a previous comment, my code generates a random permutation of your vector and checks that all these combinations are not in the permutation. If some condition is found a new permutation is generated:
vector = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18];
not_valid = 1;
while not_valid == 1
randpermutation = vector(randperm(18))
not_valid = 0;
for i = 1:length(randpermutation)-1
if randpermutation(i) == 1 && randpermutation(i+1) == 7 || randpermutation(i) == 7 && randpermutation(i+1) == 1
not_valid = 1;
end
if randpermutation(i) == 1 && randpermutation(i+1) == 8 || randpermutation(i) == 8 && randpermutation(i+1) == 1
not_valid = 1;
end
if randpermutation(i) == 1 && randpermutation(i+1) == 17 || randpermutation(i) == 17 && randpermutation(i+1) == 1
not_valid = 1;
end
if randpermutation(i) == 1 && randpermutation(i+1) == 18 || randpermutation(i) == 18 && randpermutation(i+1) == 1
not_valid = 1;
end
if randpermutation(i) == 2 && randpermutation(i+1) == 7 || randpermutation(i) == 7 && randpermutation(i+1) == 2
not_valid = 1;
end
if randpermutation(i) == 2 && randpermutation(i+1) == 8 || randpermutation(i) == 8 && randpermutation(i+1) == 2
not_valid = 1;
end
if randpermutation(i) == 2 && randpermutation(i+1) == 17 || randpermutation(i) == 17 && randpermutation(i+1) == 2
not_valid = 1;
end
if randpermutation(i) == 2 && randpermutation(i+1) == 18 || randpermutation(i) == 18 && randpermutation(i+1) == 2
not_valid = 1;
end
if randpermutation(i) == 2 && randpermutation(i+1) == 6 || randpermutation(i) == 6 && randpermutation(i+1) == 2
not_valid = 1;
end
end
end

Related

My for loop won't output anything (Matlab)

I'm trying to get this for loop to work on Matlab so I can plot these three histograms. I'm guessing it won't output because it says that my variables such as a_M_S1 keep changing size on every loop iteration, so the process is essentially inefficient. Any help? Below is the code.
I'm basically trying to generate 500 samples of 100 readings so I can then plot a histogram using estimated parameter values.
clear
clc
% Importing Data
%a = 0.9575
for m=1:500
seed=m;
rng(seed);
syms x
F=((1/atanh(0.9575))*((0.9575^(2*x-1))/(2*x-1)));
for n=1:100
data_1(n)=ceil(vpasolve(F==rand(1)));
end
Data_1(m,:)=data_1;
end
clear
clc
Data_1=[49 1 3 17 13 3 5 51 7 1
9 3 67 1 3 1 1 1 1 99
5 13 21 17 41 1 1 9 23 1
1 5 1 1 41 1 13 1 5 27
5 37 99 1 1 33 1 1 9 1
1 3 47 11 7 1 1 41 21 27
5 1 1 11 45 7 3 5 1 17
13 5 3 3 1 99 1 59 1 13
3 5 1 35 1 1 1 1 5 19
5 1 1 1 79 3 1 1 1 1
31 3 1 1 1 21 69 39 1 29
3 3 1 1 5 1 3 1 1 15
1 1 9 1 7 1 1 1 1 11
27 9 1 3 39 5 1 5 7 1
1 1 7 5 1 1 3 1 3 23
5 1 21 1 1 7 1 17 1 3
11 11 5 1 9 1 1 1 1 37
33 1 9 7 1 1 31 27 1 1
5 5 1 17 3 31 1 45 37 1
1 1 19 47 9 7 5 1 9 1
11 1 61 5 29 1 95 1 1 1
13 19 1 1 13 1 23 7 73 1
1 1 11 1 5 1 3 1 7 1
15 1 9 53 3 7 3 21 7 3
1 7 1 1 23 7 5 1 3 1
1 7 1 3 1 1 1 7 3 5
1 1 1 43 7 3 1 1 21 5
1 39 1 5 13 3 1 5 1 3
1 11 1 1 29 17 25 1 9 1
17 9 13 11 1 5 29 3 3 1
65 5 63 1 1 3 5 1 7 1
21 3 7 1 1 1 27 11 15 3
1 1 1 1 21 1 5 3 1 11
5 1 3 7 1 5 43 5 7 75
29 7 83 1 3 5 15 1 1 3
1 1 9 1 13 1 17 23 1 5
99 1 1 1 5 7 9 3 7 1
1 11 1 11 21 1 5 9 5 1
33 49 3 9 15 1 1 5 1 1
1 17 1 1 1 1 13 1 1 9
5 13 1 1 5 3 1 1 67 1
5 1 1 1 7 27 1 21 47 1
1 1 1 21 3 17 1 5 5 1
1 1 17 29 99 1 9 1 5 15
17 5 1 13 1 1 1 1 1 21
1 21 1 1 1 11 9 35 31 15
99 15 1 1 9 3 1 21 1 1
1 1 9 33 1 1 31 9 29 47
41 99 1 7 17 5 9 3 3 13
1 29 9 5 11 1 1 7 37 15];
Data_2=[1 1 3 3 5 7 1 3 1 1
1 1 1 1 1 1 1 1 1 13
5 1 5 1 1 1 1 3 1 1
1 1 3 1 1 1 1 3 1 1
1 1 13 5 1 3 1 1 5 1
3 3 1 7 3 5 3 1 3 1
1 1 1 1 1 3 3 5 1 1
1 1 1 9 1 1 1 1 5 1
1 1 1 1 1 11 7 1 5 1
17 1 1 7 3 7 3 5 5 1];
for o=1:500
syms a
%Method of Moments (MM)
mean_S1 = mean(transpose(Data_1(o,:)));
a_MM_S1(o) = vpa(vpasolve((a)/((atanh(a))*(1-a.^2)) == mean_S1,a),4);
mean_S2 = mean(transpose(Data_2(o,:)));
a_MM_S2(o) = vpa(vpasolve((a)/((atanh(a))*(1-a.^2)) == mean_S2,a),4);
%Using Lower Quantile (OS)
lower_S1 = floor(quantile(Data_1(o,:),0.25));
a_LQ_S1(o) = vpa(vpasolve((a)/(atanh(a)) == 0.25,a),4);
lower_S2 = floor(quantile(Data_2(o,:),0.25));
a_LQ_S2(o) = vpa(vpasolve((a)/(atanh(a)) == 0.25,a),4);
%Using Median (OSM)
median_S1 = floor(quantile(Data_1(o,:),0.5));
a_M_S1(o) = vpa(vpasolve((a)/(atanh(a)) == 0.5,a),4);
median_S2 = floor(quantile(Data_2(o,:),0.5));
a_M_S2(o) = vpa(vpasolve((a)/(atanh(a)) == 0.5,a),4);
end
a_MM_S1=transpose(a_MM_S1);
a_LQ_S1=transpose(a_LQ_S1);
a_M_S1=transpose(a_M_S1);
a_MM_S2=transpose(a_MM_S2);
a_LQ_S2=transpose(a_LQ_S2);
a_M_S2=transpose(a_M_S2);
figure(1)
histogram([double(a_MM_S1),double(a_MM_S2)],20),title('Method of Moments')
figure(2)
histogram([double(a_LQ_S1),double(a_LQ_S2)],20),title('Using Lower Quartile as Estimator')
figure(3)
histogram([double(a_M_S1),double(a_M_S2)],20),title('Using Median as Estimator')

one-by-one matrix assignment MATLAB

I need to find the minimum values in each column of matrix "A", and then replace those min values with the values in last row of matrix "B" (which has same number of columns). Like I have these:
>> A = randi(10,10,5)
A =
3 5 9 5 8
7 6 4 10 2
8 4 1 7 4
4 7 2 8 2
7 5 8 7 5
3 7 10 10 1
5 7 8 5 7
8 3 8 2 3
6 10 2 1 10
3 7 6 7 2
>> B = randi(100,3,5)
B =
10 34 66 18 62
99 95 49 54 81
52 1 52 9 95
>> [M,I] = min(A)
M =
3 3 1 1 1
I =
1 8 3 9 6
And I want to replace the values of "M" with "B(end,:), so that:
A(1,1) = B(end,1);
A(8,2) = B(end,2);
A(3,3) = B(end,3);
A(9,4) = B(end,4);
A(6,5) = B(end,5);
I try "A(I) = B(end,:)" and "A(I(1,:)) = B(end,:)" but they do not work! Any ideas how I could do that? My real matrices are huge (1200x100000) so no way to do it by hand!
try this to replace the first min value:
A = [ 3 5 9 5 8;
7 6 4 10 2;
8 4 1 7 4;
4 7 2 8 2;
7 5 8 7 5;
3 7 10 10 1;
5 7 8 5 7;
8 3 8 2 3;
6 10 2 1 10;
3 7 6 7 2];
B =[ 10 34 66 18 62;
99 95 49 54 81;
52 1 52 9 95];
[M,I] = min(A)
A(sub2ind(size(A),I,1:size(A,2)))=B(end,:)
the output will be:
A =
52 5 9 5 8
7 6 4 10 2
8 4 52 7 4
4 7 2 8 2
7 5 8 7 5
3 7 10 10 95
5 7 8 5 7
8 1 8 2 3
6 10 2 9 10
3 7 6 7 2
However, when you have to replace all of the min values, use the code below instead
A = [ 3 5 9 5 8;
7 6 4 10 2;
8 4 1 7 4;
4 7 2 8 2;
7 5 8 7 5;
3 7 10 10 1;
5 7 8 5 7;
8 3 8 2 3;
6 10 2 1 10;
3 7 6 7 2];
B =[ 10 34 66 18 62;
99 95 49 54 81;
52 1 52 9 95];
M = min(A);
for i=1:size(A,2)
A(find(A(:,i) == M(i)),i)=B(end,i);
end;
A
the output is:
A =
52 5 9 5 8
7 6 4 10 2
8 4 52 7 4
4 7 2 8 2
7 5 8 7 5
52 7 10 10 95
5 7 8 5 7
8 1 8 2 3
6 10 2 9 10
52 7 6 7 2
You can acces you matrix by a single index, which looks like this:
Indeces =
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
Since you get the indeces for each individual column, you just need to increase it by the column number times the height of the matrix.
This should yield the correct result:
A( I + (0 : size(A,2)-1) * size(A,1) ) = B(end,:)

How can I select rows with specific column values from a matrix?

I have a matrix train3.
1 2 3 4 5 6 7
2 12 13 14 15 16 17
3 62 53 44 35 26 17
4 52 13 24 15 26 37
I want to select only those rows of whose 1st columns contain specific values (in my case 1 and 2).
I have tried the following,
>> train3
train3 =
1 2 3 4 5 6 7
2 12 13 14 15 16 17
3 62 53 44 35 26 17
4 52 13 24 15 26 37
>> ind1 = train3(:,1) == 1
ind1 =
1
0
0
0
>> ind2 = train3(:,1) == 2
ind2 =
0
1
0
0
>> mat1 = train3(ind1, :)
mat1 =
1 2 3 4 5 6 7
>> mat2 = train3(ind2, :)
mat2 =
2 12 13 14 15 16 17
>> mat3 = [mat1 ; mat2]
mat3 =
1 2 3 4 5 6 7
2 12 13 14 15 16 17
>>
Is there any better way to do this?
Presumably you are trying to get mat3 in a single step which you can do with:
mat3 = train3(train3(:,1)==1 | train3(:,1)==2,:)
A more general way to do this would be to use ismember to get all of the rows that match the values in a list:
train3 =[
1 2 3 4 5 6 7
2 12 13 14 15 16 17
3 62 53 44 35 26 17
4 52 13 24 15 26 37];
chooseList = [1 2];
colIndex = ismember(train3(:, 1), chooseList);
subset = train3(colIndex, :);
subset =
1 2 3 4 5 6 7
2 12 13 14 15 16 17

Matlab filter matrix

My data matrix is large: smt like 180:3000 size.
Each element value is between 0 to 255;
I have to find areas in this matrix where average value is higher than some threshold (lets call it 'P'). And reset each element in these areas to '0'. Another words filter my matrix.
I have width and heigth of filter area.
So I need to loop over data matrix to find appropriate areas (As many as exist).
EDIT:
Please, see an example:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13
This is given matrix. Lets try to find areas (2, 3) of size where average value is > 15.
So the result will be:
4 6 7 5 6 6 7
10 8 9 8 9 10 9
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 5 5 5 5 5
4 5 5 5 5 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
Please, look at bottom of matrix
Please, give me some tips how it is possible to loop throw.
Thank you very much.
One way of doint this is as follows:
% example A with more areas of mean greater than 15
% there are four such areas as shown here: http://i.imgur.com/V6m0NfL.jpg
A = [16 16 16 5 16 16 16
16 16 16 8 16 16 16
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 15.1 15 15 5 5
4 5 15 15 15 5 5
10 12 12 12 13 10 11
14 15 15 16 14 15 15
13 15 15 15 14 14 13];
% filter size
[n,m] = deal(2,3);
% filter center
center = floor(([n,m]+1)/2);
% find where we have areas greater than 15
B = nlfilter(A, [n,m], #(b) mean(b(:)) > 15);
% get coordinates of areas with mean > 15
[rows,cols] = find(B);
% zero out elements in all found areas
for i = 1:size(rows,1)
% calculate starting coordinates for the area to be set to 0
row = rows(i) - center(1) + 1;
col = cols(i) - center(2) + 1;
A(row:row+n-1 , col:col+m-1) = 0;
end
Results in:
A =
0 0 0 5 0 0 0
0 0 0 8 0 0 0
10 8 9 8 9 10 9
7 4 6 9 7 8 7
4 5 0 0 0 5 5
4 5 0 0 0 5 5
10 12 12 12 13 10 11
14 0 0 0 14 15 15
13 0 0 0 14 14 13
try this
a = input_matrix;
ii = 2 ; jj = 3;
threshold = 15;
x = ones(ii,jj)/(ii*jj);
%\\create matrix temp2 with average value of block a(i:i+ii-1,j:j+jj-1) at temp2(i,j)
temp1 = conv2(a,x,'full');
temp2 = temp1(ii:end-ii+1,jj:end-jj+1);
%\\find row and column indices of temp2 with value > threshold
[row_ col_] = find(temp2>threshold);
out = a;
%\\assign zero value to the corresponding blocks
for iii = 1:length(row_)
out(row_(iii):row_(iii)+ii-1,col_(iii):col_(iii)+jj-1) = 0;
end

Extracting portions of matrix into cell array

I have a pretty large matrix M and I am only interested in a few of the columns. I have a boolean vector V where a value of 1 represents a column that is of interest. Example:
-1 -1 -1 7 7 -1 -1 -1 7 7 7
M = -1 -1 7 7 7 -1 -1 7 7 7 7
-1 -1 7 7 7 -1 -1 -1 7 7 -1
V = 0 0 1 1 1 0 0 1 1 1 1
If multiple adjacent values of V are all 1, then I want the corresponding columns of M to be extracted into another matrix. Here's an example, using the matrices from before.
-1 7 7 -1 7 7 7
M1 = 7 7 7 M2 = 7 7 7 7
7 7 7 -1 7 7 -1
How might I do this efficiently? I would like all these portions of the matrix M to be stored in a cell array, or at least have an efficient way to generate them one after the other. Currently I'm doing this in a while loop and it is not as efficient as I'd like it to be.
(Note that my examples only include the values -1 and 7 just for clarity; this isn't the actual data I use.)
You can utilize the diff function for this, to break your V vector into blocks
% find where block differences exist
diffs = diff(V);
% move start index one value forward, as first value in
% diff represents diff between first and second in original vector
startPoints = find(diffs == 1) + 1;
endPoints = find(diffs == -1);
% if the first block begins with the first element diff won't have
% found start
if V(1) == 1
startPoints = [1 startPoints];
end
% if last block lasts until the end of the array, diff won't have found end
if length(startPoints) > length(endPoints)
endPoints(end+1) = length(V);
end
% subset original matrix into cell array with indices
results = cell(size(startPoints));
for c = 1:length(results)
results{c} = M(:,startPoints(c):endPoints(c));
end
The one thing I'm not sure of is if there's a better way to find the being_indices and end_indices.
Code:
X = [1 2 3 4 5 1 2 3 4 5
6 7 8 9 10 6 7 8 9 10
11 12 13 14 15 11 12 13 14 15
16 17 18 19 20 16 17 18 19 20
1 2 3 4 5 1 2 3 4 5
6 7 8 9 10 6 7 8 9 10
11 12 13 14 15 11 12 13 14 15
16 17 18 19 20 16 17 18 19 20];
V = logical([ 1 1 0 0 1 1 1 0 1 1]);
find_indices = find(V);
begin_indices = [find_indices(1) find_indices(find(diff(find_indices) ~= 1)+1)];
end_indices = [find_indices(find(diff(find_indices) ~= 1)) find_indices(end)];
X_truncated = mat2cell(X(:,V),size(X,1),[end_indices-begin_indices]+1);
X_truncated{:}
Output:
ans =
1 2
6 7
11 12
16 17
1 2
6 7
11 12
16 17
ans =
5 1 2
10 6 7
15 11 12
20 16 17
5 1 2
10 6 7
15 11 12
20 16 17
ans =
4 5
9 10
14 15
19 20
4 5
9 10
14 15
19 20