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

4 views (last 30 days)
Doli Swey on 13 Sep 2020
Commented: Doli Swey on 16 Sep 2020
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!

Bruno Luong on 14 Sep 2020
Unzip this attached file, you'll get a pfile r1234.p
Call it
A = r1234
You'll get the result as specified.

Doli Swey on 15 Sep 2020
This is amazing. Thank you so much Bruno.
Bruno Luong on 16 Sep 2020
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
Doli Swey on 16 Sep 2020
Thank you so much Bruno.

Walter Roberson on 13 Sep 2020
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.

Doli Swey on 14 Sep 2020
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?
Walter Roberson on 14 Sep 2020
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.
Doli Swey on 15 Sep 2020
Great Thank you Walter. I have learn a lot by your coding mentality. All the best!