I am faced with the following programming problem. I need to generate n
(a, b)
tuples for which the sum of all a
's is a given A
and sum of all b
's is a given B
and for each tuple the ratio of a / b
is in the range (c_min, c_max)
. A / B
is within the same range, too. I am also trying to make sure there is no bias in the result other than what is introduced by the constraints and the a / b
values are more-or-less uniformly distributed in the given range.
Some clarifications and meta-constraints:
A
, B
, c_min
, and c_max
are given. A / B
is in the (c_min, c_max)
range. This has to be so if the problem is to have a solution given the other constraints.>0
and non-integer.I am trying to implement this in Python but ideas in any language (English included) are much appreciated.
Method 1: Using Math. random() function is used to return a floating-point pseudo-random number between range [0,1) , 0 (inclusive) and 1 (exclusive). This random number can then be scaled according to the desired range.
One way to generate these numbers in C++ is to use the function rand(). Rand is defined as: #include <cstdlib> int rand(); The rand function takes no arguments and returns an integer that is a pseudo-random number between 0 and RAND_MAX.
A true random number generator (TRNG), also known as a hardware random number generator (HRNG), does not use a computer algorithm. Instead, it uses an external unpredictable physical variable such as radioactive decay of isotopes or airwave static to generate random numbers.
Lots of good ideas here. Thanks! Rossum's idea seemed the most straightforward implementation-wise so I went for it. Here is the code for posterity:
c_min = 0.25
c_max = 0.75
a_sum = 100.0
b_sum = 200.0
n = 1000
a = [a_sum / n] * n
b = [b_sum / n] * n
while not good_enough(a, b):
i, j = random.sample(range(n), 2)
li, ui = c_min * b[i] - a[i], c_max * b[i] - a[i]
lj, uj = a[j] - c_min * b[j], a[j] - c_max * b[j]
llim = max((li, uj))
ulim = min((ui, lj))
q = random.uniform(llim, ulim)
a[i] += q
a[j] -= q
i, j = random.sample(range(n), 2)
li, ui = a[i] / c_max - b[i], a[i] / c_min - b[i]
lj, uj = b[j] - a[j] / c_max, b[j] - a[j] / c_min
llim = max((li, uj))
ulim = min((ui, lj))
q = random.uniform(llim, ulim)
b[i] += q
b[j] -= q
The good_enough(a, b)
function can be a lot of things. I tried:
(a_sum / n, b_sum / n)
(though that's trivial to fix).0
is desirable. But it has the same drawbacks as kurtosis.n
. 2n
sometimes wasn't enough, n ^ 2
is a little bit of overkill and is, well, exponential.Ideally, a heuristic using a combination of skewness and kurtosis would be best but I settled for making sure each value has been changed from the initial (again, as rossum suggested in a comment). Though there is no theoretical guarantee that the loop will complete, it seemed to work well enough for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With