Is there an efficient way to generate a random combination of N integers such that—
min
, max
],
Here is the algorithm from John McClane's PermutationPartitionGenerator, in another answer on this page. It has two phases, namely a setup phase and a sampling phase, and generates n
random numbers in [min
, max
] with the sum sum
, where the numbers are listed in random order.
Setup phase: First, a solution table is built using the following formulas (t(y, x)
where y
is in [0, n
] and x
is in [0, sum - n * min
]):
Here, t(y, x) stores the relative probability that the sum of y
numbers (in the appropriate range) will equal x
. This probability is relative to all t(y, x) with the same y
.
Sampling phase: Here we generate a sample of n
numbers. Set s
to sum - n * min
, then for each position i
, starting with n - 1
and working backwards to 0:
v
to a random integer in [0, t(i+1, s)).r
to min
.v
.v
remains 0 or greater, subtract t(i, s-1) from v
, add 1 to r
, and subtract 1 from s
.i
in the sample is set to r
.EDIT:
It appears that with trivial changes to the algorithm above, it's possible to have each random number use a separate range rather than use the same range for all of them:
Each random number at positions i
∈ [0, n
) has a minimum value min(i) and a maximum value max(i).
Let adjsum
= sum
- Σmin(i).
Setup phase: First, a solution table is built using the following formulas (t(y, x)
where y
is in [0, n
] and x
is in [0, adjsum
]):
The sampling phase is then exactly the same as before, except we set s
to adjsum
(rather than sum - n * min
) and set r
to min(i) (rather than min
).
EDIT:
For John McClane's CombinationPartitionGenerator, the setup and sampling phases are as follows.
Setup phase: First, a solution table is built using the following formulas (t(z, y, x)
where z
is in [0, n
], y
is in [0, max - min
], and x
is in [0, sum - n * min
]):
Sampling phase: Here we generate a sample of n
numbers. Set s
to sum - n * min
and mrange
to max - min
, then for each position i
, starting with n - 1
and working backwards to 0:
v
to a random integer in [0, t(i+1, mrange, s)).mrange
to min(mrange
, s
)mrange
from s
.r
to min + mrange
.i
, mrange
, s
) from v
.v
remains 0 or greater, add 1 to s
, subtract 1 from r
and 1 from mrange
, then subtract t(i
, mrange
, s
) from v
.i
in the sample is set to r
.