Creating all pairings and comparing to correct pairing
First, define a function to generate all pairings, and a function to generate the correct pairing:
def all_pairings(l):
if len(l) == 0:
return [[]]
else:
return [[(l[0],l[i])] + p for i in range(1,len(l)) for p in all_pairings(l[1:i]+l[i+1:])]
def adjacent_pairing(l):
it = iter(l)
return zip(it, it)
Then it's just a for-loop:
children = ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2']
correct_pairing = set(adjacent_pairing(children))
for pairing in all_pairings(children):
sentence = 'Found' if set(pairing) == correct_pairing else 'Not found'
print(', '.join(''.join(pair) for pair in pairing), ' -- ', sentence)
Output:
a1a2, b1b2, c1c2, d1d2 -- Found
a1a2, b1b2, c1d1, c2d2 -- Not found
a1a2, b1b2, c1d2, c2d1 -- Not found
a1a2, b1c1, b2c2, d1d2 -- Not found
...
a1d2, a2d1, b1b2, c1c2 -- Not found
a1d2, a2d1, b1c1, b2c2 -- Not found
a1d2, a2d1, b1c2, b2c1 -- Not found
Shuffling the pairings
I suggest using random.shuffle
to shuffle the possible pairings before iterating (otherwise, the correct pairing is always the first pairing generated, which is a bit boring).
import random
l = list(all_pairings(children))
random.shuffle(l)
for pairing in l:
sentence = 'Found' if set(pairing) == correct_pairing else 'Not found'
print(', '.join(''.join(pair) for pair in pairing), ' -- ', sentence)
Output:
a1a2, b1d2, b2d1, c1c2 -- Not found
a1d1, a2d2, b1c2, b2c1 -- Not found
a1b2, a2c2, b1c1, d1d2 -- Not found
...
a1b1, a2c2, b2d1, c1d2 -- Not found
a1a2, b1b2, c1c2, d1d2 -- Found
a1b2, a2c2, b1d2, c1d1 -- Not found
...
a1c2, a2d2, b1b2, c1d1 -- Not found
a1c2, a2d2, b1c1, b2d1 -- Not found
a1b1, a2b2, c1c2, d1d2 -- Not found
Probability of finding the correct pairing
Assuming all pairings are equiprobable, the probability of finding the correct pairing when picking one pairing randomly is 1 divided by the total number of distinct possible pairings.
How many distinct possible pairings are there?
Choosing an ordered pairing, where the order of the pairs matter, and the order of the two children in each pair matter, is the same as choosing a permutation. It is well known that there are N!
possible permutations of N
children.
How many ordered pairings correspond to each unordered pairing?
There are 2 possible ways to order the 2 children in each pair; thus there are 2 ** (N / 2)
ways to order the 2 children of all pairs.
There are (N / 2)!
possible ways to order the N / 2
pairs.
Thus, each pairing corresponds to (N / 2)! * 2 ** (N / 2)
ordered pairings.
Thus, there must be N! / ( (N / 2)! * 2 ** (N / 2) )
distinct possible pairings of N
children.
For your 8 children, that's 8! / (4! * 2**4) == 105
.
The probability of picking the correct pairing, when picking uniformly at random amongst all distinct possible pairings, is 1 over that number:
just slightly under 1% in the case of 8 children.
Expected number of correct pairs in a random pairing
Let's pick a pairing at random among all distinct possible pairings. How many of the pairs in that pairing will be correct, in average?
We can count the number of correct pairs in each pairing in our python program:
for pairing in all_pairings(children):
nb_correct_pairs = len(set(pairing) & correct_pairing)
print(', '.join(''.join(pair) for pair in pairing), ' -- ', nb_correct_pairs)
Output:
a1a2, b1b2, c1c2, d1d2 -- 4
a1a2, b1b2, c1d1, c2d2 -- 2
a1a2, b1b2, c1d2, c2d1 -- 2
a1a2, b1c1, b2c2, d1d2 -- 2
a1a2, b1c1, b2d1, c2d2 -- 1
a1a2, b1c1, b2d2, c2d1 -- 1
a1a2, b1c2, b2c1, d1d2 -- 2
a1a2, b1c2, b2d1, c1d2 -- 1
...
a1d2, a2c1, b1d1, b2c2 -- 0
a1d2, a2c2, b1b2, c1d1 -- 1
a1d2, a2c2, b1c1, b2d1 -- 0
a1d2, a2c2, b1d1, b2c1 -- 0
a1d2, a2d1, b1b2, c1c2 -- 2
a1d2, a2d1, b1c1, b2c2 -- 0
a1d2, a2d1, b1c2, b2c1 -- 0
The average number is actually easy to calculate with mathematics.
Let us consider one particular child in a random pairing, for instance child a1
. What is the probability that child a1
will hold their twin's hand? Since there are N-1
other children, and by symmetry all children are equally likely, the probability that child a1
will hold their twin's hand is 1/(N-1)
.
Of course, this applies to all children, not just a1
. Thus, in average, 1/(N-1)
of the children will hold their own twin's hand. Since there are N
children, then in average, N/(N-1) == 1 + 1/(N-1)
children will hold their own twin's hand. Since there are 2 children per pair, that means that in average, there will be N / (2(N-1)) == (1 + 1/(N-1)) / 2
correct pairs in a random pairing.
In the case of N == 8
, this means 4/7 ≈ 0.571
correct pairs per pairing.
Let us verify experimentally:
l = list(all_pairings(children))
total_correct_pairs = sum(len(set(pairing) & correct_pairing) for pairing in l)
n_pairings = len(l)
expected_correct_pairs = total_correct_pairs / n_pairings
print('Expected number of correct pairs: ', expected_correct_pairs)
Output:
Expected number of correct pairs: 0.5714285714285714