1

I would very much like to generate n random integer numbers between two values (min, max) whose sum is equal to a given number m.

Note: I found similar questions in StackOverflow; however, they do not address exactly this problem (use of Dirichlet function and thus numbers between 0 and 1).

Example: I need 8 random numbers (integers) between 0 and 24 where the sum of the 8 generated numbers must be equal to 24.

Any help is appreciated. Thanks.

toolic
  • 57,801
  • 17
  • 75
  • 117
Ania
  • 83
  • 7
  • 2
    What have you tried so far? Maybe we can help out if we have something to go on... – Stephen C Dec 26 '18 at 21:15
  • 2
    Well that's hardly "random". Do you mean find all the sets of 8 integers from 0 to 24 which add to 24, then choose one of them at random? (If so, the first part is somewhat interesting and the second is trivial, so it basically comes down to the first part.) – Robin Zigmond Dec 26 '18 at 21:16
  • Read [this](https://stackoverflow.com/questions/19877059/generate-n-random-numbers-in-given-ranges-that-sum-up-to-a-given-sum) and the Wiki link to get the algorithm – Sheldore Dec 26 '18 at 21:22
  • You could use multinomial like https://stackoverflow.com/questions/53279807/how-to-get-random-number-list-with-fixed-sum-and-size/53355454#53355454 – Severin Pappadeux Dec 26 '18 at 21:28

3 Answers3

1

Well, you could use integer distribution which naturally sums to some fixed number - Multinomial one.

Just shift forth and back, and it should work automatically

Code

import numpy as np

def multiSum(n, p, maxv):
    while True:
        v  = np.random.multinomial(n, p, size=1)
        q  = v[0]
        a,  = np.where(q > maxv) # are there any values above max
        if len(a) == 0: # accept only samples below or equal to maxv
            return q

N = 8
S = 24
p = np.full((N), 1.0/np.float64(N))

mean  = S / N
start = 0
stop  = 24
n = N*mean - N*start

h = np.zeros((stop-start), dtype=np.int64)
print(h)
for k in range(0, 10000):
    ns = multiSum(n, p, stop-start) + start # result in [0...24]
    #print(np.sum(ns))
    for v in ns:
        h[v-start] += 1

print(h)
Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64
1

this is a case of partition number theory . here is solution .

def partition(n,k,l, m):
    if k < 1:
        raise StopIteration
    if k == 1:
        if n <= m and n>=l :
            yield (n,)
        raise StopIteration
    for i in range(l,m+1):
        for result in partition(n-i,k-1,i,m):                
            yield result+(i,)

n = 24 # sum value
k = 8 # partition size
l = 0 # range min value
m = 24 # range high value 

result = list(partition(n,k,l,m ))

this will give all the combinations that satisfy the conditions. ps this is quite slow as this is giving all the cases for that partition size.

sahasrara62
  • 10,069
  • 3
  • 29
  • 44
0

This is one possible solution which is based on this answer. it seems the dirichlet method is only functional for between 0 and 1. Full credit should be given to the original answer. I will be happy to delete it once you comment that it served your purpose.

Don't forget to upvote the original answer.

target = 24

x = np.random.randint(0, target, size=(8,))
while sum(x) != target: 
    x = np.random.randint(0, target, size=(8,))

print(x)
# [3 7 0 6 7 0 0 1]
Sheldore
  • 37,862
  • 7
  • 57
  • 71