Nx4 Table of randi(1,M) so that the columns are not equal and each number only repeats P times

2 views (last 30 days)
Nathaniel H Werner on 4 Jan 2023
Edited: Jiri Hajek on 5 Jan 2023
I need to create an N x 4 table array that where each column contains random integers between 1 and M. However the number of times each of the random number repeats in a single column cannot exceed a specific number P and must also not equal the value in the preceeding column.
Here is some code setting up the first two columns.
c1 = {'A';'B';'C';'D';...
'E';'F';'G';'H';...
'I';'J';'K';'L';'M'};
M = 4;
N = 13;
P = [4,3,4,3]; % 1, 2, 3, 4
c2 = [1;3;2;4;3;4;1;4;3;1;2;3;1];
disp(table(c1,c2,'VariableNames',{'Names','Arbitrary'}))
Names Arbitrary _____ _________ {'A'} 1 {'B'} 3 {'C'} 2 {'D'} 4 {'E'} 3 {'F'} 4 {'G'} 1 {'H'} 4 {'I'} 3 {'J'} 1 {'K'} 2 {'L'} 3 {'M'} 1
Notice, I chose the numbers between 1 and 4 (M = 4) arbitrarily for the second column. This means ...
• P = 4 for 1.
• P = 3 for 2.
• P = 4 for 3.
• P = 3 for 4.
To make things easier, I want to maintain this arrangement of P for each integer in the next column.
I think this question helps me generate the random numbers in the third column, but I am not sure how to make sure there are P = 4 1's, P = 3 2's etc.
c3 = zeros(N,1);
for i=1:N
vv = setdiff(1:M,c2(i));
r = randi(M-1,1);
c3(i) = vv(r);
end
disp(table(c1,c2,c3,'VariableNames',...
{'Names','Arbitrary','Third Column'}))
Names Arbitrary Third Column _____ _________ ____________ {'A'} 1 2 {'B'} 3 1 {'C'} 2 1 {'D'} 4 3 {'E'} 3 1 {'F'} 4 3 {'G'} 1 4 {'H'} 4 3 {'I'} 3 4 {'J'} 1 2 {'K'} 2 3 {'L'} 3 1 {'M'} 1 4
P1 = sum(c3==1)
P1 = 4
P2 = sum(c3==2)
P2 = 2
P3 = sum(c3==3)
P3 = 4
P4 = sum(c3==4)
P4 = 3
So now I have the third column of random integers between 1 and M excluding c2(i) for every name, but I have no idea how to make sure the number of each integer follows the criteria set apart. The same problem will persist when I make the fourth column where the value cannot equal that in c3(i).
Aside from generating the random numbers, I'm stuck.
Dyuman Joshi on 5 Jan 2023
So if I am understanding correct, if the distribution in 2nd column is
4 1's
3 2's
4 3's
2 4's
The distribution in 3rd column should not equal to any of the values of above, the # of repetitions of 1-4 must be different. (Similar for 4th column as well, not matching with 2nd or 3rd)
And you want this for 3 columns (2nd, 3rd and 4th)?
Are the values of M, N and P fixed for this problem? (4, 13 and the [4 3 4 3] respectively)

Jiri Hajek on 5 Jan 2023
Edited: Jiri Hajek on 5 Jan 2023
Hi, I think you can use an algorithm which essentially mimics your prescription like the following code snippet. There is just the first column, but it is straightforward to extend to cover all four. Note that depending on the values of N, M and P, it can happen quite easily that the generation of the matrix will fail.
% Definitions
N = 30;
M = 20;
P = 10;
% Is solution possible?
if M*P <= N
error('solution is not possible');
end
%% First column
firstColumn = zeros(N,1); % First column - just random numbers below M
availableNumbers = 1:M; % unique integers below M == [1:M]
while nnz(firstColumn) < N
% check if there are still available numbers
if isempty(availableNumbers)
disp(firstColumn)
error('first column generation error: no available numbers, %d unassigned positions',nnz(~firstColumn))
end
% choose one of the available numbers and eliminate it from future choices
idx = randi(length(availableNumbers));
xi = availableNumbers(idx);
availableNumbers(idx) = [];
% choose the number of occurences
Pxi = randi(min(P,N-nnz(firstColumn)));
% choose random indexes to place the selected xi
for i = 1:Pxi
ifree = find(firstColumn == 0);
nfree = length(ifree);
inew = randi(nfree);
firstColumn(ifree(inew)) = xi;
end
end
disp(firstColumn)

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

R2021b

Community Treasure Hunt

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

Start Hunting!