import itertools import math import random def rank(p, elements): k = len(p) if k == 1: return len(list(e for e in elements if e < p[0])) head, tail = p[0], p[1:] n = len(elements) - 1 num_preceding = len([e for e in elements if e < head]) preceding = num_preceding * ( math.factorial(n) / math.factorial(n - k + 1) ) return int(preceding) + rank(tail, elements - {head}) def unrank(index, n, k): return [0] n = 4 k = 2 for p in sorted(itertools.chain.from_iterable(map( lambda x: list(itertools.permutations(x)), itertools.combinations(range(n), k)))): print((p, rank(list(p), set(range(n))))) n = 2048 k = 24 p = random.sample(range(n), k) print((p, rank(p, set(range(n))))) num_tests = 0 max_n = 20 max_k = 5 for _ in range(num_tests): n = random.randint(5, max_n) k = random.randint(2, min(max_k, n)) p = random.sample(range(1, n + 1), k) elements = set(range(n)) rank_p = rank(p, elements) unranked = unrank(rank_p, 0, 0) if unranked != p: print((p, n, rank_p, unranked, rank(unranked, elements))) break
Standard input is empty
((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)