> func (r *Rand) Perm(n int) []int {
> m := make([]int, n)
> for i := 0; i < n; i++ {
> m[i] = i
> }
> for i := 0; i < n; i++ {
> j := r.Intn(i + 1)
> m[i], m[j] = m[j], m[i]
> }
> return m
> }
>
> So, I see, that the array gets mixed - somehow. However:
> Does this code actually distribute uniformly? Or is this some sort
> of old, standard algorithm I'm gonna find in Knuth's TAOCP4?
> It's not obvious to me - maybe someone can illustrate that for me.
It's an old, standard algorithm you're gonna find in Knuth's TAOCP2.
Knuth presents it as Algorithm P in Section 3.4.2 of Volume 2, crediting
it to Fisher and Yates (1938) and Durstenfeld (1964).
If Intn generates a uniformly distributed random integer from 1 to n,
then the code above generates a uniformly distributed random
permutation. At the beginning of each iteration, m[0:i] is a uniformly
distributed random permutation of the original m[0:i], and m[i:] is
just the original sequence. The loop body randomizes the location
of m[i] by swapping it with a randomly chosen location j in [0, i].
It's not a proof, but a good sanity check is to look at the sequence
of calls to Intn: Intn(1), Intn(2), Intn(3), ..., Intn(n). Taken as a whole,
there are 1*2*...*n = n! possible result sequences, which is equal to
the number of possible permutations we wanted to generate.
Of course, Intn does not generate truly random integers: it eventually cycles.
Knuth also mentions an article by Salfi (1974) that points out that if the
underlying random generator has a period m then you can't possibly
get a uniform distribution when n! > m because the generator can
only generate m different permutations. I'm not sure of the math
behind Intn, but it looks to me like the generator has 38,000 bits of
state. If all of that ends up contributing to the period then that's good
for generating uniform permutations of size up to n=3000 or so.
For uniformly distributed larger permutations where it is important
that every permutation is possible, you'd need to hook the algorithm to
a better random number generator.
Russ