pseudorandomize using brute force

Hi,
I have a vector consisted of 79 ones and 316 zeros. I would like to randomly order my vector so that a "1" can only occur after 3 or more zeros occur consecutively. So, my codes is as following:
A = [zeros(316,1); ones(79,1)];
%shuffle randomly
nTrials = size(A,1);
RandTrials = randperm(nTrials)';
A(:,2)=RandTrials(:,1);
A=sortrows(A,2);
for t=RandTrials %runs A vector by vector
if A(t,1)==1 & A(t-1,1)==0 & A(t-2,1)==0 & A(t-3,1)==0
; %do nothing
elseif A(t,1)==1 & A(t-1,1)==1;
RandTrials = randperm(nTrials)';
A(:,2)=RandTrials(:,1);
A=sortrows(A,2);
elseif A(t,1)==1 & A(t-1,1)==1 & A(t-1,2)==1;
RandTrials = randperm(nTrials)';
A(:,2)=RandTrials(:,1);
A=sortrows(A,2);
elseif A(t,1)==1 & A(t-1,1)==1 & A(t-1,2)==1 & A(t-1,3)==1;
RandTrials = randperm(nTrials)';
A(:,2)=RandTrials(:,1);
A=sortrows(A,2);
end
end
I was wondering what I am doing wrong in this code. Hope someone can help me on this.
Thanks in advance,
Nil

2 Comments

Please recheck the number of zeros. 315 or 316?
Hi Walter,
Thanks! I just edited that part although that was not crucial. I also realized the confusion on number of zeros and number of ones that you pointed out in your first comment and edited that.

Sign in to comment.

Answers (2)

If a 1 can only occur after 3 or more zeros, then you need at least 3 times as many 0 as you have 1. As you have 315 ones, you would need at least 945 zeros.
Note: your code accidentally reverses the number of 0's and 1's.

2 Comments

You might want to have a look at http://www.mathworks.com/matlabcentral/answers/282617-how-to-do-this-operation-on-a-random-matrix#comment_364318 and grab my partitions routine there and modify it to have a minimum number of items per partition. The idea would be that you would partition (total length minus number of ones) into (number of ones) pieces, each of minimum length 3, and then you would take [zeros(1, number_in_partition), 1] as the substructure.
Thank you very much for your reply. Actually, your codes seem a bit advanced to me as I am new to Matlab. Another suggestion I get from a colleague today was to find the derivates from the first 1 to the second 1, from the second 1 to the third 1 and so on. This will be inside a while loop that has 100000 (or so) iterations to shuffle the vector. Inside that while, run a loop that if the derivate is larger than 3, it will break the loop; if not, it will return while loop many times (i.e., 100000). The only downside of this is to take so much time to finish.
Thanks,
Nil

Sign in to comment.

John D'Errico
John D'Errico on 8 Jun 2016
Edited: John D'Errico on 8 Jun 2016
Even after the repair, correcting the number of zeros and ones...
You have 79 ones, and 316 zeros. The requirement is that a one may ONLY appear after 3 zeros have appeared.
So at the very best, a 1 may appear at position 4, then 8, then 12, etc. You see the pattern. The indexes of the ones elements appear at locations:
(1:79)*4
Ok, that is a COMPLETELY non-random sequence. But is it the shortest possible such sequence. It would account for
3*79
ans =
237
Thus 237 zeros.
316 - 3*79
ans =
79
You wish to always have 316 zeros. So there must be 79 more zeros.
The solution is now trivial. Just start with the NON-random sequence.
S = zeros(1,316);
S(4:4:316) = 1;
Now, choose random insertion points, and add a zero at that location. You can do it using a loop if you wish, one zero at a time. This is the simplest solution.
for i = 1:79
ns = numel(S);
% New location of a zero,
% after the newind location in S
newind = randi(ns+1,1) - 1;
S = [S(1:newind),0,S((newind+1):end);
end
I'm feeling too lazy to do it more intelligently, but that would be entirely possible too. Since it is hardly worthwhile to optimize code that is not yet asking to be optimized...

3 Comments

Hi John,
Thank you very much for this. Sorry for the confusion, but actually this is not nonrandom because it is not true that 1s only be in the position of 4th, 8th, 12th, and so on. That would destroy my experiment. In fact, 1s can occur after 3, 4, 5, 6, 7,... (and so on) times of 0s. For instance, I can accept such order:
A=[0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1]
Therefore, I would like to randomly assign the number of zeros between the two 1s. The reason I cannot accept such an order: A=[0 0 1 1 0 1 0 0 ] is that 1s are novel sounds and 0s are regular (only one sound) sound. I would like to test the alertness of the participants. If novel sounds (i.e., 1s) occur consecutively, then they would not alert the participant. If the number of 0s/regular sounds are predictable, so in the case of the novel sound occur in the same position (i.e., 4th, 8th, 12th..), that would not alert/surprise participants, too. So, I would like to have a reasonable and random regular/normal sound between the two novel sounds.
The reason I select 79 and 316 is that novel sounds should play 1/5 of all the sounds as it has been tried and found to be working before. Although nothing magical in particularly 79 and 316; it needs to be always the same ratio: 1s should be 1/4 of the 0s.
P.S: my 100000 iterations that I mentioned previously as reply to Walter does not seem to work for that ratio and such big numbers although it was working in a small number of vector. So, any further suggestion would be helpful.
Thank you in advance.
I believe that you misunderstood John's suggestion. He says the following:
  • Create a nonrandom sequence of 0 and 1 having the property that you want, using all but 79 of your zeros
  • Insert the 79 other zeros into the nonrandom sequence in a random way.
I believe that this is a fine idea, satisfying your requirements in all respects, and is an efficient computational scheme.
Alan Weiss
MATLAB mathematical toolbox documentation
John D'Errico
John D'Errico on 9 Jun 2016
Edited: John D'Errico on 9 Jun 2016
Alan is completely correct. While it starts out as non-random, once you are done inserting randomly placed zeros, it is exactly that, and it has the property that you want to see, AND it is quite efficient.
The virtue of the scheme that I have proposed is in the end, you do have a fully random sequence that fits all of your requirements. Were you to try instead to choose how many zeros to place between the ones, then you would have a serious problem of assuring both that the total number of zeros is what was specified, and that every one has at least 3 zeros.
In fact, this is a fairly tightly constrained problem. You don't have that many spare zeros to insert there. On average, you will have 4 zeros between every one, but since you know that you MUST have at least 3 zeros, then there will be very few cases where you can have too many zeros separating a pair of ones.

Sign in to comment.

Asked:

on 7 Jun 2016

Edited:

on 9 Jun 2016

Community Treasure Hunt

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

Start Hunting!