Conditional Random number generation

Hello there, For example; If I want to generate 5 random integer numbers with a sum of 20, how can I do that?
" ... example = ceil(10*rand(100, 5)) ... "

1 Comment

Why did you edit away your question? It is stored on Google cache anyway, so it's easy to restore.

Sign in to comment.

 Accepted Answer

function R = randfixedsumint(m,n,S);
% This generates an m by n array R. Each row will sum to S, and
% all elements are all non-negative integers. The probabilities
% of each possible set of row elements are all equal.
% RAS - Mar. 4, 2017
if ceil(m)~=m|ceil(n)~=n|ceil(S)~=S|m<1|n<1|S<0
error('Improper arguments')
else
P = ones(S+1,n);
for in = n-1:-1:1
P(:,in) = cumsum(P(:,in+1));
end
R = zeros(m,n);
for im = 1:m
s = S;
for in = 1:n
R(im,in) = sum(P(s+1,in)*rand<=P(1:s,in));
s = s-R(im,in);
end
end
end
return

6 Comments

Thanks, Roger.
Could I point you to https://www.mathworks.com/matlabcentral/answers/327941-row-column-summation-constraints-in-random-binary-matrix ? My reframing of the problem there gets down to a constrained version of integer partitioning, where there is a per-bucket maximum.
Hello Walter & Roger, I just wanted to mention a certain way using the the partition method, which produces one vector 'c' at a time. I know how to vectorize it to make a matrix but have not done so yet (famous last words!). I make no claims on how this might compare with Roger's version.
% n = number of terms
% s = the sum
% zero allowed
a = randperm(s+n-1);
b = [0 a(1:n-1) s+n]; % 'a' makes up the separators
c = diff(sort(b))-1;
% zero not allowed
if n > s
error('sum is not large enough since all integers are >=1');
end
a = randperm(s-1);
b = [0 a(1:n-1) s]; % 'a' makes up the separators
c = diff(sort(b));
Regards both of you: I have developed and used your function. Since I need to make a random vector having a sum of all array equal to 20 and it does not have any zero in. Meanwhile, in my case, the maximum number is moved in the middle.
S = 20;
n = 5;
m = 1;
while true
P = ones(S+1,n);
for in = n-1:-1:1
P(:,in) = cumsum(P(:,in+1));
end
R = zeros(m,n);
for im = 1:m
s = S;
for in = 1:n
R(im,in) = sum(P(s+1,in)*rand<=P(1:s,in));
s = s-R(im,in);
end
end
x = find(R<=0);
if x~=0
continue
else
break
end
end
indMaxArry = ceil(n/2);
R = circshift(sort(R),[0,indMaxArry])
please, how can I modify this code to have values between 1 and s/2 ?
Wondering whether it is possible to specify the max and min of the devided value? i.e., something like what you kindly provided in the randfixedsum function, thanks!
Ref
@Walter Roberson "Wondering whether it is possible to specify the max and min of the devided value?"

Sign in to comment.

More Answers (2)

9 Comments

Unfortunately, the numbers from ‘randfixedsum’ will rarely be integers. However, I can conceive of a method of rounding and sorting its results which would transform such numbers into integers with the proper sum. I’m too sleepy to work on it for now - tomorrow maybe.
In the case of integers, one approach is to work with Partitions . Unfortunately the partitions routines I see at the moment are designed to list all of the possibilities rather than to choose one at random.
@Roger: What about creating the numbers with the sum 20*2^53 by randfixedsum and dividing the values by 2^53? This might cause some inaccuracies in the last bit due to rounding, but this might be negligible for the OP.
wang syr
wang syr on 2 Mar 2017
Edited: wang syr on 2 Mar 2017
Unfortunately, randfixedsum doesn't generate right.
For example; "aaa= ceil(randfixedsum(10,10,300,3,31))" >>> row sum values: 301, 299, 306, etc.
@syracus syr: That is not how I would do the correction.
I just thought of a completely different method for the case where you have a fixed sum of a fixed number of positive integers:
random_posint_partition = @(of_what, num_rows, number_of_partitions) accumarray( [repmat((1:num_rows).',of_what, 1), randi(number_of_partitions, num_rows*of_what, 1)], 1);
Example run:
>> random_posint_partition(20,7,5)
ans =
4 3 4 5 4
5 3 3 5 4
3 6 1 6 4
3 6 4 5 2
5 3 6 2 4
4 6 8 1 1
5 1 6 4 4
>> sum(ans,2)
ans =
20
20
20
20
20
20
20
That is, the first parameter gives the number which is to be partitioned, the second parameter gives the number of different times you want the generation to be done, and the third parameter gives the number of pieces to partition into.
... I thought it would be a lot harder to come up with a fair method!
Oops, I just discovered that this can generate entries with a count of 0. :( For example,
6 5 5 4 0
The adjusted version is
random_posint_partition = @(of_what, num_rows, number_of_partitions) 1 + accumarray( [repmat((1:num_rows).',of_what-number_of_partitions, 1), randi(number_of_partitions, num_rows*(of_what-number_of_partitions), 1)], 1);
@Walter. The distribution of values one gets with this method you have described depends very heavily upon the assumption that is made about the underlying statistics involved. By my calculations, using your method, the probability of getting the result [4,4,4,4,4] is 305,540,235,000 times as likely as that of getting the result [20,0,0,0,0]. (I’m assuming your original method, which would allow zero integers.) It is equivalent to tossing 20 pebbles into 5 cans at random and recording the sum of pebbles in each can. In other words, the distribution is heavily weighted in favor of roughly equal values among the five integers.
However, suppose you assume instead that you are in a five dimensional “hyper-cube” of integer space, each integer of which can vary from 0 to 20, and that each integer-valued point in this cube has an equal a priori probability, namely, 1/(21^5). Then suppose, as a conditional probability, that we restrict ourselves to the subset in which the five integers must have 20 as their sum. Such a conditional probability distribution will give [4,4,4,4,4] and [20,0,0,0,0] an equal conditional probability, as opposed to the above enormous difference. This latter kind of conditional probability is analogous to the kind of conditional probability assumption that is the basis of my ‘randfixedsum’ algorithm #9700 for continuous distributions. If we were to use an integer adjustment to the results of randfixedsum, this latter is roughly the kind of integer distribution we would obtain.
Ah. I don't think I know how to implement your suggestion, though, at least not without generating all of the possible choices that sum to 20 and then picking one at random.
John D'Errico's https://www.mathworks.com/matlabcentral/fileexchange/12009-partitions-of-an-integer can calculate all of the possible partitions; a question is whether we can avoid having to take that step.
https://en.wikipedia.org/wiki/Partition_(number_theory)#Restricted_part_size_or_number_of_parts talks about restricted partitioning briefly, and ties it to change making problems, which does indeed sound equivalent to the approach I was taking. Those are in turn tied to knapsack problems.

Sign in to comment.

m = 5;
n = 3;
s = 10;
This will generate uniform distribution with sum criteria
% generate non-negative integer random (m x n) array row-sum to s
[~,r] = maxk(rand(m,s+n-1),n-1,2);
z = zeros(m,1);
r = diff([z, sort(r,2), (s+n)+z],1,2)-1;

1 Comment

While generating conditional random numbers, how can we generate random numbers that has a limit of some maximum value and have certain specified sum value?

Sign in to comment.

Categories

Find more on Random Number Generation 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!