jeudi 23 avril 2020

Is there an efficient way to generate a combination of random integers in a range that have a given average?

Is there an efficient way to generate a random combination of N integers such that—

  • each integer is in the interval [min, max],
  • the combination of integers has a mean of mean, and
  • the combination is chosen uniformly at random from among all possible combinations?

I am aware that this problem can be solved in the following way:

  1. Use the algorithm given in Smith and Tromble ("Sampling from the Unit Simplex", 2004) to generate N random non-negative integers with the sum N * mean - N * min.
  2. Add min to each number generated this way.
  3. If any number is greater than max, go to step 1.

However, this algorithm is slow if max is much less than N * mean. For example, according to my tests, the algorithm rejects, on average—

  • about 1.6 samples if N = 7, min = 3, max = 10, mean = 6, but
  • about 30.6 samples if N = 20, min = 3, max = 10, mean = 6.

Is there a way to modify this algorithm to be efficient for large N while still meeting the requirements above?

The following code example is given in Ruby, but my question is independent of programming language:

def posintwithsum(n, total)
    raise if n <= 0 or total <=0
    ls = [0]
    ret = []
    while ls.length < n
      c = 1+rand(total-1)
      found = false
      for j in 1...ls.length
        if ls[j] == c
          found = true
          break
        end
      end
      if found == false;ls.push(c);end
    end
    ls.sort!
    ls.push(total)
    for i in 1...ls.length
       ret.push(ls[i] - ls[i - 1])
    end
    return ret
end

def integersWithSum(n, total)
  raise if n <= 0 or total <=0
  ret = posintwithsum(n, total + n)
  for i in 0...ret.length
    ret[i] = ret[i] - 1
  end
  return ret
end

# Generate 100 combinations
mn=3
mx=10
mean=6
n=7
100.times {
  while true
    pp=integersWithSum(n,n*mean-n*mn).map{|x| x+mn }
    if !pp.find{|x| x>mx }
      p pp; break # Output the sample and break
    end
  end
}



Aucun commentaire:

Enregistrer un commentaire