The Cheryl’s Birthday puzzle that took the social networks by storm is a variant of the Sum And Product puzzle. Note that these articles contain the solutions.

Let’s imagine that two mathematicians are told independently and in secret the sum and the product of two different numbers from [2, 100] range. The one that knows the sum is able to declare that the other one does not know the original numbers either. Having heard this one that knows the product states that now he knows the secret pair. In response to that the first mathematician also declares the knowledge of the original numbers.

Upon seeing this puzzle I decided to solve it in Python in a logical and readable way. While the solution works, I’m not happy with the readability. In fact it turned out that the Wikipedia Suma Nad Product puzzle page contains a Python solution that seems to be simpler than mine. Oh well.

Here’s my code for the curious.

import itertools import collections import sys r = [ (x, y) for x in range(2, 101) for y in range(2, 101) if x + y <= 100 and x < y ] def allSums(r): return set(elem[0] + elem[1] for elem in r) def allProducts(r): return set(elem[0] * elem[1] for elem in r) def havingSum(s, r): return [e for e in r if e[0] + e[1] == s] def havingProduct(p, r): return [e for e in r if e[0] * e[1] == p] def flatten(z): return list(v for v in itertools.chain.from_iterable(z)) allSums0 = allSums(r) # "sum" mathematician does not know so the sum is ambiguous sStmt0 = flatten([ havingSum(s, r) for s in allSums0 if len(havingSum(s, r)) > 1 ]) allSums1 = allSums(sStmt0) selSums1 = [ s for s in allSums1 if min(len(havingProduct(e[0] * e[1], sStmt0)) for e in havingSum(s, sStmt0)) >= 2 ] # "product" mathematician cannot know so these are the numbers for which products are ambiguous sStmt1 = flatten(havingSum(s, sStmt0) for s in selSums1) # "product" mathematician now knows, so these are the filtered products for which solutions are unique selProd1 = sorted([ p for p in allProducts(sStmt1) if len(havingProduct(p, sStmt1)) == 1 ]) # and here are the pairs pStmt2 = sorted(flatten([havingProduct(p, sStmt1) for p in selProd1])) sumCount = collections.Counter([ e[0] + e[1] for e in pStmt2 ]) solutionSumList = [ x for x in sumCount if sumCount[x] == 1 ] # finally the solution if len(solutionSumList) == 1: solutionSum = solutionSumList[0] solutionList = havingSum(solutionSum, pStmt2) if len(solutionList) == 1: solution = solutionList[0] print("Solution:", solution) sys.exit(0) print("Solution unknown") sys.exit(1)