# Generate random integers that sums to a specific number within a specific range

67 views (last 30 days)
Yu Takahashi on 10 Feb 2021
Edited: Matt J on 11 Feb 2021
Dear members
I am attempting to generate random integers that sums to a specific number within a specific range. Infact, Roger Stafford provided a similar function randfixedsumint, but lacking the ability for specifying the min and max value that each integers could go.
In other words, I am looking for a function that could randomly generate 3 integers that sums to 1000 within a gange of 100 <= x <= 700.
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
Ref_1
Quite similar to what randfixsum(Random Vectors with Fixed Sum) could achieve, but I am having trouble limiting the generated value as just integers
Ref_2
Conditional Random number generation
##### 2 CommentsShowHide 1 older comment
Yu Takahashi on 10 Feb 2021
thanks for your comment, but I am having trouble turning this into a generalizable function. Specifically I was constantly prompt with "Too many output arguments."
The function I was aiming at:
input : sum(i.e., 1000), number of elements(i.e., 3), min(i.e., 100), max (i.e., 700)

Matt J on 10 Feb 2021
Edited: Matt J on 11 Feb 2021
Quite similar to what randfixsum(Random Vectors with Fixed Sum) could achieve, but I am having trouble limiting the generated value as just integers
I think a good approximate solution would be to use randfixedsum to get an initial continuous-space randomization x0. Then, you can use minL1intlin (Download) to project x0 to the nearest (in L1-norm) integer solution x. I don't know if this will be perfectly uniformly distributed, but I think it will be close. Example:
n=7; %number of variables
s=3000; %constrained sum
lb=100; %lower bound
ub=700; %upper bound
x0=randfixedsum(n,1,s,lb,ub);
e=ones(1,n);
x=round( minL1intlin( speye(n), x0, 1:n, [],[],e,s,lb*e,ub*e) );
>> [x0,x]
ans =
337.2273 337.0000
238.0432 238.0000
623.6036 624.0000
416.6231 417.0000
581.9920 582.0000
649.9868 650.0000
152.5241 152.0000
>> sum(x)
ans =
3000

Matt J on 10 Feb 2021
Edited: Matt J on 10 Feb 2021
For such a small problem size, you can pre-generate a table of allowable combinations:
[x,y]=ndgrid(uint16(100:700));
z=1000-x(:)-y(:);
idx=100<=z & z<=700;
comboTable = [x(idx),y(idx),z(idx)];
N=size(comboTable,1);
Then, you can just select rows randomly from the table:
xyz=comboTable(randi(N,1),:)
xyz = 1×3
571 313 116
Yu Takahashi on 10 Feb 2021
thanks a lot for the help, this is pretty clever! However, for my other use cases which required the combination of up to 7 humbers, with greater summing number of (e.g., 3000), this would be problematic(as you kindly pointed out in your answer). That is why I am looking for a more generalized function that might solve my problem once and for all.

Bruno Luong on 10 Feb 2021
Edited: Bruno Luong on 10 Feb 2021
Unfortunately the uniform distribution with bounds for integer is much more challenging. One way is to approximate by rounding the results
lo = 100;
hi = 700;
s = 3000;
n = 7;
if n*ceil(lo) > s || s*floor(hi) < s
error('Not possible')
end
while true
x = randfixedsum(n,1,s,lo,hi);
c = round([0; cumsum(x)]); c(end)=s;
xi = diff(c);
if all(xi >= lo & xi <= hi)
break
end
end
xi