fork download
  1. import itertools
  2. import math
  3. import random
  4.  
  5.  
  6. def rank(p, elements):
  7. k = len(p)
  8.  
  9. if k == 1:
  10. return len(list(e for e in elements if e < p[0]))
  11.  
  12. head, tail = p[0], p[1:]
  13.  
  14. n = len(elements) - 1
  15. num_preceding = len([e for e in elements if e < head])
  16.  
  17. preceding = num_preceding * (
  18. math.factorial(n)
  19. / math.factorial(n - k + 1)
  20. )
  21.  
  22. return int(preceding) + rank(tail, elements - {head})
  23.  
  24.  
  25. def unrank(index, n, k):
  26. return [0]
  27.  
  28.  
  29. n = 4
  30. k = 2
  31.  
  32. for p in sorted(itertools.chain.from_iterable(map(
  33. lambda x: list(itertools.permutations(x)),
  34. itertools.combinations(range(n), k)))):
  35. print((p, rank(list(p), set(range(n)))))
  36.  
  37. n = 2048
  38. k = 24
  39. p = random.sample(range(n), k)
  40. print((p, rank(p, set(range(n)))))
  41.  
  42. num_tests = 0
  43. max_n = 20
  44. max_k = 5
  45.  
  46. for _ in range(num_tests):
  47. n = random.randint(5, max_n)
  48. k = random.randint(2, min(max_k, n))
  49.  
  50. p = random.sample(range(1, n + 1), k)
  51. elements = set(range(n))
  52.  
  53. rank_p = rank(p, elements)
  54. unranked = unrank(rank_p, 0, 0)
  55.  
  56. if unranked != p:
  57. print((p, n, rank_p, unranked, rank(unranked, elements)))
  58. break
Success #stdin #stdout 0.12s 14880KB
stdin
Standard input is empty
stdout
((0, 1), 0)
((0, 2), 1)
((0, 3), 2)
((1, 0), 3)
((1, 2), 4)
((1, 3), 5)
((2, 0), 6)
((2, 1), 7)
((2, 3), 8)
((3, 0), 9)
((3, 1), 10)
((3, 2), 11)
([1511, 995, 80, 456, 503, 625, 1823, 363, 165, 443, 554, 1473, 1816, 517, 500, 1205, 1559, 597, 1358, 1600, 1965, 99, 1514, 66], 19109087003151058954278674398784049781016523296216161242241175256034702566758429)