views:

582

answers:

4

I want to simulate N-dimensional biased die?

def roll(N,bias):
     '''this function rolls N dimensional die with biasing provided'''
     # do something
     return result

>> N=6
>> bias=( 0.20,0.20,0.15,0.15,0.14,0.16,)
>> roll(N,bias)
   2
+4  A: 

More language agnostic, but you could use a lookup table.

Use a random number in the range 0-1 and lookup the value in a table:

0.00 - 0.20   1
0.20 - 0.40   2
0.40 - 0.55   3
0.55 - 0.70   4
0.70 - 0.84   5
0.84 - 1.00   6
Gamecat
In the context of biased dies, it might pay to mention the uniform distribution of the random number :)
Greg Hewgill
+8  A: 

A little bit of math here.

A regular die will give each number 1-6 with equal probability, namely 1/6. This is referred to as uniform distribution (the discrete version of it, as opposed to the continuous version). Meaning that if X is a random variable describing the result of a single role then X~U[1,6] - meaning X is distributed equally against all possible results of the die roll, 1 through 6.

This is equal to choosing a number in [0,1) while dividing it into 6 sections: [0,1/6), [1/6,2/6), [2/6,3/6), [3/6,4/6), [4/6,5/6), [5/6,1).

You are requesting a different distribution, which is biased. The easiest way to achieve this is to divide the section [0,1) to 6 parts depending on the bias you want. So in your case you would want to divide it into the following: [0,0.2), [0.2,0.4), [0.4,0.55), 0.55,0.7), [0.7,0.84), [0.84,1).

If you take a look at the wikipedia entry, you will see that in this case, the cumulative probability function will not be composed of 6 equal-length parts but rather of 6 parts which differ in length according to the bias you gave them. Same goes for the mass distribution.

Back to the question, depending on the language you are using, just translate this back to your die roll. In Python, here is a very sketchy, albeit working, example:

import random
sampleMassDist = (0.2, 0.1, 0.15, 0.15, 0.25, 0.15)

# assume sum of bias is 1
def roll(massDist):
    randRoll = random.random() # in [0,1)
    sum = 0
    result = 1
    for mass in massDist:
        sum += mass
        if randRoll < sum:
            return result
        result+=1

print roll(sampleMassDist)
Yuval A
There is a small issue here. The floating point numbers have limited accuracy, and therefore the sum of the weights will typically not be exactly 1. I don't know how important this effect is, but it may be safer to use integers for the weights instead.
Wim Coenen
@wcoenen: They're *random* numbers. No distribution of random numbers can ever precisely match the given bias. If the set of numbers matched the given bias, we'd have to reject it as not actually random.
S.Lott
Thanks for very good mathematical explaination.
TheMachineCharmer
+3  A: 
import random

def roll(sides, bias_list):
    assert len(bias_list) == sides
    number = random.uniform(0, sum(bias_list))
    current = 0
    for i, bias in enumerate(bias_list):
        current += bias
        if number <= current:
            return i + 1

The bias will be proportional.

>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
6
>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
2

Could use integers too (better):

>>> print roll(6, (10, 1, 1, 1, 1, 1))
5
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 5, 5, 10, 4, 8))
2
>>> print roll(6, (1,) * 6)
4
nosklo
Thanks for suggesting clean solution.
TheMachineCharmer
A: 

See the recipe for Walker's alias method for random objects with different probablities.
An example, strings A B C or D with probabilities .1 .2 .3 .4 --

abcd = dict( A=1, D=4, C=3, B=2 )
  # keys can be any immutables: 2d points, colors, atoms ...
wrand = Walkerrandom( abcd.values(), abcd.keys() )
wrand.random()  # each call -> "A" "B" "C" or "D"
                # fast: 1 randint(), 1 uniform(), table lookup

cheers
-- denis

Denis
looks cool but would you please elaborate ?
TheMachineCharmer
David, for a biased die / a 1d distribution over a few points,table lookup is just fine, Walker's method overkill;for distributions of say many stars in 3d, use Walker.(Did the recipe / its refs make any sense at all ?)
Denis