How can I pseudorandomize with constrains and make spesific number spread equally among the array?

Hello everybody,
I have a question regarding to pseudorandomization and more. Sorry I am new on Matlab and I feel very stuck!
I have an array consist of 4 numbers (1,2,3,4). The lenght of the array is 330. Number 1,2,3 are repeated 100 times, whereas number 4 is repeated 30 (%10 of total)times.
A=[1,1,2,3,4,2,3.....]
How can I randomize this array in a way that the maximum number of repetition of spesific number is 3 (for expample [1,3,2,2,2,2,1,1,1,3,..] is not correct) and
the number 4 is positioned more less equily spreed along the array (like in every 8-12 position)?
Thank you very much.
Stay happy and healthy!

 Accepted Answer

Unzip this attached file, you'll get a pfile r1234.p
Call it
A = r1234
You'll get the result as specified.

7 Comments

Wow thats amazing.Thank you sooo much!!!!
But I have rounded the numbers for the sake of the conversation and now I cannot edit with this file type =/ Would it be so much trouble to make this with 120 1s,2s,3s, and 36 4s (rather than 100 1,2,3 and 30 4s) ? Sorry if I cause so much trouble. Or you can teach me how to modify it?
Hi Bruno
Thank you for bearng with me, but I think you forgot to change the numbers of 4s, from 30 to 36. Because I am getting an array of 390 instead of 396.
Please dont hate me ^^
Oops sorry I didn't read you changed the number of 4s.
Here is the updated version
Here is the code in clear
function [G, I] = r1234(nset, m, cmax, mlast)
% [G, I] = r1234(nset, m, cmax)
% Generate a random of nset groups of numbers
% Each group contains 1:nset elements
% with constraint no more than cmax same-group is consecutively generated
% G and I are arrays of size 1 x n, with n = nset*m
% G contains group number
% I contains order with in a group (values in 1:m)
% NOTE: [G, I] = r1234(nset, m, cmax, mlast)
% the last group only has mlast elements
if nargin < 1
nset = 3;
m = 120; % number of samples for 1s, 2, ... nset
mlast = 36; % number of samples 4
cmax = 3; % maximum succesive condition
else
if nargin < 4
mlast = m;
end
end
% This define the desired frequency of 1, 2, 3s, three time more 1s than 3s
c = cumsum(cmax:-1:1);
c = [0 c]/c(end);
[~,i] = histc(rand(1,m),c); %#ok
i = cumsum(i);
l = diff([0,i(1:find(i<m,1,'last')),m]);
% Generate same number of groups for each number
% each group has 1,...ncmax elements
c = cell(1,nset);
q = length(l); % number of groups
for j=1:nset
k = randperm(m)+(j-1)*m;
p = mat2cell(k,1,l);
p = p(randperm(end)); % shuffle groups
c{j} = p;
end
c = cat(1,c{:});
% permute randomly consecutive groups of 1s, 2s, 3s with the constraints
% that they don't repeat at the frontier
[~,r] = sort(rand(size(c)),1);
r = mod(r+cumsum([0,r(end,1:end-1)==r(1,2:end)]),nset)+1;
c = c((0:q-1)*nset+r);
c = cat(2,c{:});
G123 = ceil(c/m);
I123 = mod(c,m)+1;
n = nset*m;
if mlast < m
% Insert 4s
s4 = floor(n/mlast)+1;
i4 = (0:mlast-1)*s4+randi(s4-1,1,mlast); % distribute more or less 4s uniformly
% however never followed each_other
b = accumarray(i4(:),1,[n+mlast,1]);
b = logical(b.');
else
b = false(1,n);
end
G = zeros(size(b))+(nset+1);
G(~b) = G123;
I = zeros(size(b));
I(b) = randperm(mlast);
I(~b) = I123;
end

Sign in to comment.

More Answers (1)

the number 4 is positioned more less equily spreed along the array (like in every 8-10 position)?
You cannot achieve that constraint.
If you were to distribute the 30 entries that are 4 equally across the 330 positions, they would have to be every 11 apart. If you put them closer together (maximum 10 apart) then that can only occupy at most 300 of the 330 entries, leaving an uncovered gap of at least 15 on both sides. If you say that the minimum distance must be 8 and the maximum must be 10, then you cannot spread the 30 entries out over the 330 elements of the array without ending up with a portion of the array for which that does not hold.

7 Comments

Dear Walter, thank you for your quick reply. You are absoulutely correct, I am modifying the interval as (9-11) as your suggestion. Thank you.
9-11 would stil force them to be 11 apart in order to be able to fit the 30 distinguished values in the vector of length 330.
30*11 = 330. If even one location had only 10 instead of 11, the maximum coverage would be 29*11+10 = 329 and so there would have to be at least one location that was 12 away instead of at most 11 away.
You have to permit 12 or more if you want some values less than 11.
I understand the concern. In order to have better felixibility I have made it 8-12. Thank you Walter.
N = 30;
offsets = 11 * ones(1,N);
%the following guarantees that sum(offsets) stays the same
%K = 50 rounds is arbitrary
for K = 1 : 50
PQ = randperm(N, 2);
if offsets(PQ(1)) < 12 & offsets(PQ(2)) > 8
offsets(PQ(1)) = offsets(PQ(1)) + 1;
offsets(PQ(2)) = offsets(PQ(2)) - 1;
end
end
position4 = cumsum(offsets) - randi(offsets(1)-1);
Now the 4's go at the positions indicated in position4.
Alright. Walter thank you. I understand the logic of selecting the position for number 4s. Much appreciated..
Now, I have to fill the rest of the array. How am I going to fill the rest of the array with 1s,2s and 3s with no more than 3 repetition, would you help me in this part also?
I suggest starting with
NB = 100;
M = [1 * ones(1,Nb), 2 * ones(1,NB), 3 * ones(1,NB)];
M = M(randperm(length(M)));
Now assign 4s into your result vector at locations position4, and assign M into your result vector at locations that are not position4
results = zeros(1,NB*3+N);
results(position4) = 4;
results(~ismember(1:NB*3+N, position4)) = M;
After that I would suggest scanning results looking for more than 3 in a row and taking that element and exchanging it with a random location that is not the same value and is not a 4 and where it will not trigger 4+ in a row.
Great Thank you Walter. I have learn a lot by your coding mentality. All the best!

Sign in to comment.

Categories

Asked:

on 13 Sep 2020

Commented:

on 16 Sep 2020

Community Treasure Hunt

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

Start Hunting!