Tricky randomization issue - help needed!
Show older comments
Dear Matlab folks,
I am struggling with the following issue:
I created 80 parings of numbers. These pairings should stay the same but the order of the pairings should be randomized.
So, I have a variable containing these pairings: sequence = [pairing_1 pairing_2 pairing_3 and so forth].
How can I randomize the order of these pairings? For example, it would look like this then: randomized_sequence = [pairing_2 pairing_3 pairing_1 .....]
And now for the tricky part:
The numbers of the pairings reach from 1 to 40. Every number from 1 to 40 is combined with one random even number between 1 and 40 and one random uneven number between 1 and 40. For 1, I could have the pairings 1 & 18 and 1 & 9 for example. But 1 must not be paired with 1! No number can be matched with itself. Furthermore, 1 must not be paired with 2 and 2 must not be paired with 1, the sequence doesn't matter. 3 must not be paired with 4, 5 must not be paired with 6 and so forth until 39 must not be paired with 40 and every time, the sequence doesn't matter. So, 39 and 40 is not possible as well as 40 and 39.
The numbers that must not be paired are:
1 2 | 3 4 | 5 6 | 7 8 | 9 10 | 11 12 | 13 14 | 15 16 | 17 18 | 19 20 | 21 22 | 23 24 | 25 26 | 27 28 | 29 30 | 31 32 | 33 34 | 35 36 | 37 38 | 39 40
So 2 and 3 can be paired, for example!
Now the problem is, if I have these 2 pairings 14 16 and 16 9 and after the shuffling of the pairings 14 16 lands before 16 9 then I have a 16 16 pairing as well which must not happen. Such unwanted pairings can happen a lot through the shuffling. For example, the 14 of 14 16 must not be preceeded by 14 or 13 and the 16 of 14 16 must not be followed by 16 or 15.
I was thinking about maybe coding something like: "If 1 is followed/preceded by 1 or 2 then shuffle again. If 2 is followed/preceded by 1 or 2 then shuffle again. If 3 is followed/preceded by 3 or 4 then shuffle again...." and so forth until "If 40 is followed/preceded by 40 or 39 then shuffle again."
What do you think, is there a way to do it like that? Or even a way easier solution, I did not think about?
I very much appreciate any help, this is bothering me since quite some time now.
Thanks in advance,
Rupert
7 Comments
It may take a long time to generate valid shiuffle if you need to exclude many of them.
How did you store the pairs? I hope you used an array instead of numbered variables.
Can you give a small example of input and valid output? You can make the example smaller (e.g. 6 instead of 40).
Rupert Steinmeier
on 25 Aug 2020
Edited: Rik
on 25 Aug 2020
Rik
on 25 Aug 2020
OK, let's first create an array with all pairs:
N=6;
all_ids=(1:N)';
odd=all_ids(1:2:end);
even=all_ids(2:2:end);
pair_with_even=even(randi(end,N,1));
pair_with_odd=odd(randi(end,N,1));
list_of_pairs=[all_ids pair_with_odd;all_ids pair_with_even];
list_of_pairs([1:2:end 2:2:end],:)=list_of_pairs;
Now you want to shuffle this. What exactly do you mean by preceding? Should the list be made linear, like you wrote in text?
Also note that it is generally a bad idea to use variables with numbers in them if you plan to do something with these numbers. Try to use arrays (i.e. matrices) instead of a long list of variables. And if you don't know the difference (after seeing my code): I would urge you to do the Matlab OnRamp tutorial. It is free and will teach you the Matlab basics.
(also: avoid the length function; you should use numel or size instead, because length can cause unexpected behavior if your input is not a vector)
Rupert Steinmeier
on 26 Aug 2020
Rik
on 26 Aug 2020
So by preceding you mean preceding, well, that cleared up your definition.
Let's linearize the array I generated:
reshape(list_of_pairs.',1,[])
%returns this list if rng(1) is put at the start of the code:
%1 1 1 4 2 3 2 6 3 3 3 2 4 3 4 2 5 3 5 2 6 5 6 2
Does it matter your horizontal bars are gone?
Can you try to write a function that will check if a sequence is valid? At least in words?
Rupert Steinmeier
on 26 Aug 2020
Rik
on 26 Aug 2020
It does take a while: 20370 tries if you shuffle the list, 884 tries if you don't.
Accepted Answer
More Answers (1)
Mohammad Sami
on 25 Aug 2020
Edited: Rik
on 25 Aug 2020
One option can be to generate a sequence longer then you need and then eliminate values until the sequence is valid. Thereafter you can take desired length of sequence. If it's shorter generate again and concatenate it.
DesiredLength = 200;
N = 2 * DesiredLength;
Seq = randi([1 40],N,1);
while(any(abs(diff(Seq))<=1))
I = [false;abs(diff(Seq)) <= 1];
Seq(I) = [];
if(length(Seq)<DesiredLength)
Seq = [Seq;randi([1 40],N,1)];
end
end
Final = Seq(1:DesiredLength);
5 Comments
Rik
on 25 Aug 2020
I assume you were on mobile, so I took the liberty of editing your code.
Mohammad Sami
on 26 Aug 2020
Thanks Rik :)
Rupert Steinmeier
on 26 Aug 2020
Mohammad Sami
on 26 Aug 2020
Based on your description I assumed that the sequence is valid if the absolute difference between two consecutive number is > 1. So the code is essentially checking if the sequence is valid in the while loop. If there is any value where the absolute difference is less then or equal to 1 it is removed. The if statement just checks if the sequence is longer then the length you need after removing invalid values. In that case it generates and append more data. The while loop will terminate once there is no invalid pairing left.
Rupert Steinmeier
on 26 Aug 2020
Categories
Find more on Entering Commands in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!