The brilliant engineers at <enter company you love to hate> have struck again. This time they've "revolutionised" the generation of random permutations. "Every great invention is simple" they say and their magical new algorithm is as follows:
- Start with a list
1,2,3,...,n
of numbers to permute. - For each element x in the list draw a random index in the list and swap x and the element at the random index
Then they "prove" that this is unbiased because each element occurs at each position with equal frequency.
Obviously, their reasoning is flawed because their method has n^n
equally likely outcomes which typically is not a multiple of n!
Your task is as follows: Write a program / function that accepts a list / stream / generator / iterator (whatever makes most sense in your language of choice) of permutations and decides whether they are a biased sample as created by the algorithm above or not. If not you may assume that the sample is unbiased.
n
will be 3
or more. You can set a minimum sample size as you see fit,
Your program may err on small samples but must converge to the correct answer as the sample size increases.
You may output True/False or any two values (but not groups of values: so for example empty list vs. nonempty list is not allowed unless the nonempty list is always the same)
Apart from that standard rules apply.
This is code-golf, smallest function or program in bytes wins. Different languages compete independently.
Python 3 Test case generator
import random
def f(n,biased=True,repeats=10,one_based=False):
OUT = []
for c in range(repeats):
out = [*range(one_based,n+one_based)]
OUT.append(out)
for i in range(n):
o = random.randint(i-i*biased,n-1)
out[o],out[i] = out[i],out[o]
return OUT
Additional hints
Now that @AndersKaseorg has let the cat out of the bag I see no harm in giving a few more hints.
Even though it may look plausible at first sight it is not true that elements are uniformly distributed over positions.
We do know:
Directly after the nth element was swapped with a random position the element at position n is truly uniformly random. In particular, in the final state the last position is uniformly random.
Before that the nth element is guaranteed to be equal or smaller than n
Whatever is swapped downwards from position n to m can only be returned to n at the nth move. In particular, it can't be if the original move was the nth in the first place.
If we rank positions by their expectation after the kth move then positions m and n can overtake each other only at the mth or nth move.
Select values:
The base (i.e. first or zeroth) element's position is uniformly random. This holds after the first swap and remains true from there on.
The next element is over-represented in the first position: Out of
n^n
possible draws it occurs in(n-1) x n^(n-2) + (n-1)^(n-1)
instances.The last element is under-represented in the first position: Out of
n^n
possible draws it occurs in2 x (n-1)^(n-1)
instances.
5 can be used to solve this challenge in a similar but perhaps slightly less golfable way to Anders's answer.