How to create a random permutation that has specific values in a specific place?

I am trying to get a trial order that randomises between sequences but not within. This code works for my purposes:
temp(1).compound = {'G'};
temp(2).compound = {'R'};
temp(3).compound = {'A'};
temp(4).compound = {'RA'};
temp(5).compound = {'B'};
temp(6).compound = {'B'};
temp(7).compound = {'G'};
temp(8).compound = {'B'};
temp(9).compound = {'G'};
temp(10).compound = {'R'};
temp(11).compound = {'RA'};
sequence1(1) = 3;
sequence2(1)=1;
sequence2(2)=7;
sequence2(3)=9;
sequence3(1)=2;
sequence3(2)=4;
sequence3(3)=10;
sequence3(4)=11;
sequence4(1)=5;
sequence5(1)=6;
sequence5(2)=8;
sequenece = {sequence1, sequence2, sequence3, sequence4, sequence5};
ind = randperm(numel(sequenece));
shuffled_sequenece = [sequenece{ind}];
for i = 1:length(temp)
TRIAL(i)=temp(shuffled_sequenece(i));
end
I need all sequences to be in TRIAL but I want sequence1 or sequence4 to be randomly fixed at trial number 6. How could I do this?

2 commentaires

@William Nicholson: using numbered variables is a sign that you are doing something wrong. Trying to access variable names dynamically is one way that beginners force themselves into writing slow, complex, buggy code that is hard to debug. Read this to know more:
Your code would be simpler and much more efficient if you just used indexing.
QUESTION: do the index vectors within sequence need to be kept together, or can they be split by element 6? For example, if the index vectors of sequence sequence are arranged like this:
[[1,7,9], [2,4,10,11], ...] ->
[ 1, 7, 9, 2, 4, 10, 11, ... ]
^^ sixth element
then the sixth element is 10: what do you want done to this sequence: split it apart, something like this:
[1,7,9,2,4,5,10,11,...]
^^^^ split and insert one of the required indices?
Apologies for not being clear enough but index vectors within sequence need to be kept together and not split by element 6.
So this would be a valid order: [1 7 9], [6 8], 3, [2 4 10 11], 5
but this would not be: [1 7 9], [2 4 5 10 11]

Connectez-vous pour commenter.

 Réponse acceptée

Stephen23
Stephen23 le 24 Août 2018
Modifié(e) : Stephen23 le 25 Août 2018
One simple solution is to keep generating permutations until one matches your requirements:
C = {'G','G','A','G','B','G','G','G','G','G','RA'};
S = {3, [1,7,9], [2,4,10,11], 5, [6,8]};
X = zeros(1,11);
while ~any(X(6)==[S{[1,4]}])
X = [S{randperm(numel(S))}];
end
Z = C(X) % Don't use a loop! This is MATLAB, so just use indexing.
In theory this might never reach a solution, but for small problems, like the one in your question, it will be quite fast in practice. Note that I used a cell array for simplicity: if you really need a structure, just add this:
TRIAL = struct('compound',Z)
If your actual problem is larger then you might need to consider a more heavy-handed approach. One possibility is to determine all permutations which place either of the two scalar values into the sixth element of X (the method I show here assumes that both S{1} and S{4} are scalar, that there are no other scalars, and that there are no empty arrays). For large problems a recursive function might be more efficient, but here I cheated and just used perms:
S = {3, [1,7,9], [2,4,10,11], 5, [6,8]};
L = cellfun('prodofsize',S);
P = perms(1:numel(S));
Y = sum(ismember(cumsum(L(P),2),[5,6]),2)==2;
M = P(Y,:)
giving a matrix M where each row is one permutation (not random!) of the index vectors in S such that one of the scalar values S{1} or S{4} ends up in the sixth element:
M =
5 2 4 3 1
5 2 4 1 3
5 2 1 4 3
5 2 1 3 4
4 3 1 5 2
4 3 1 2 5
3 4 1 5 2
3 4 1 2 5
3 1 4 5 2
3 1 4 2 5
2 5 4 3 1
2 5 4 1 3
2 5 1 4 3
2 5 1 3 4
1 3 4 5 2
1 3 4 2 5
Then all you need to do is randomly pick one row from that matrix to use as the index:
X = M(randi(size(M,1)),:);
Z = C(X) % Don't use a loop!

Plus de réponses (1)

Writing multiple sequentially-numbered variables is a bad idea in general but won't try to get into fixing that here...but if were indexed or struct fields or other ways to implement wouldn't have to rewrite code lines...
if rand<0.5
sequence = {sequence1, sequence2, sequence3, sequence4, sequence5};
else
sequence = {sequence4, sequence2, sequence3, sequence1, sequence5};
end
if I get your intent.

3 commentaires

Thanks! This does work but I actually have many sequences and need to have more than two random permutations. Would there be a way to automate this rather than having to type out a lot of sequence options?
Yeah, but as noted you need to store the data in arrays or named fields in a struct in order to address it dynamically rather than using sequentially-named variables.
Having stored the data in a cell array I still wish for sequence1 ('3') or sequence4 ('5') to be randomly fixed at trial number 6 in TRIAL. How could I do this?
if true
temp(1).compound = {'G'};
temp(2).compound = {'G'};
temp(3).compound = {'A'};
temp(4).compound = {'G'};
temp(5).compound = {'B'};
temp(6).compound = {'G'};
temp(7).compound = {'G'};
temp(8).compound = {'G'};
temp(9).compound = {'G'};
temp(10).compound = {'G'};
temp(11).compound = {'RA'};
sequence = {3, [1 7 9], [2 4 10 11], 5, [6 8]};
rand_ind=randperm(length(sequence));
sequence_random=sequence(rand_ind);
Shuffled_sequence = cell2mat(sequence_random);
for i = 1:length(temp)
TRIAL(i)=temp(Shuffled_sequence(i));
end
end

Connectez-vous pour commenter.

Catégories

Produits

Version

R2014b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by