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 update_p(p, i, n):
  26. p[i] += 1
  27. prev = p[:i]
  28. while p[i] in prev:
  29. p[i] += 1
  30. for j in range(i + 1, len(p)):
  31. p[j] = 0
  32. prev = p[:j]
  33. while p[j] in prev:
  34. p[j] += 1
  35.  
  36.  
  37. def unrank(index, k, n):
  38. elements = sorted(range(n))
  39. p = elements[:k]
  40. remaining = index
  41. for i in range(k):
  42. if p[i] == n - 1:
  43. continue
  44. while True:
  45. r = rank(p, set(elements))
  46. if r > remaining:
  47. break
  48. update_p(p, i, n)
  49. print((p,r))
  50. candidate = remaining - r
  51. remaining = candidate
  52. return p
  53.  
  54. n = 4
  55. k = 2
  56.  
  57. for p in sorted(itertools.chain.from_iterable(map(
  58. lambda x: list(itertools.permutations(x)),
  59. itertools.combinations(range(n), k)))):
  60. print((p, rank(list(p), set(range(n)))))
  61.  
  62. n = 2048
  63. k = 24
  64. p = random.sample(range(n), k)
  65. # print((p, rank(p, set(range(n)))))
  66.  
  67. num_tests = 1
  68. max_n = 20
  69. max_k = 5
  70.  
  71. for _ in range(num_tests):
  72. n = random.randint(5, max_n)
  73. k = random.randint(2, min(max_k, n))
  74.  
  75. p = random.sample(range(n), k)
  76. p, k, n = [6, 2], 2, 14
  77. elements = set(range(n))
  78.  
  79. rank_p = rank(p, elements)
  80. unranked = unrank(rank_p, k, n)
  81.  
  82. if unranked != p:
  83. print((p, n, rank_p, unranked, rank(unranked, elements)))
  84. break
Success #stdin #stdout 0.15s 14196KB
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)
([1, 0], 0)
([2, 0], 13)
([3, 0], 26)
([4, 0], 39)
([5, 0], 52)
([6, 0], 65)
([7, 0], 78)
([6, 2], 14, 80, [7, 0], 91)