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 update_p(p, i, n):
p[i] += 1
prev = p[:i]
while p[i] in prev:
p[i] += 1
for j in range(i + 1, len(p)):
p[j] = 0
prev = p[:j]
while p[j] in prev:
p[j] += 1
def unrank(index, k, n):
elements = sorted(range(n))
p = elements[:k]
remaining = index
for i in range(k):
if p[i] == n - 1:
continue
while True:
r = rank(p, set(elements))
if r > remaining:
break
update_p(p, i, n)
print((p,r))
candidate = remaining - r
remaining = candidate
return p
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 = 1
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(n), k)
p, k, n = [6, 2], 2, 14
elements = set(range(n))
rank_p = rank(p, elements)
unranked = unrank(rank_p, k, n)
if unranked != p:
print((p, n, rank_p, unranked, rank(unranked, elements)))
break
aW1wb3J0IGl0ZXJ0b29scwppbXBvcnQgbWF0aAppbXBvcnQgcmFuZG9tCgoKZGVmIHJhbmsocCwgZWxlbWVudHMpOgogIGsgPSBsZW4ocCkKCiAgaWYgayA9PSAxOgogICAgcmV0dXJuIGxlbihsaXN0KGUgZm9yIGUgaW4gZWxlbWVudHMgaWYgZSA8IHBbMF0pKQoKICBoZWFkLCB0YWlsID0gcFswXSwgcFsxOl0KCiAgbiA9IGxlbihlbGVtZW50cykgLSAxCiAgbnVtX3ByZWNlZGluZyA9IGxlbihbZSBmb3IgZSBpbiBlbGVtZW50cyBpZiBlIDwgaGVhZF0pCgogIHByZWNlZGluZyA9IG51bV9wcmVjZWRpbmcgKiAoCiAgICAgIG1hdGguZmFjdG9yaWFsKG4pCiAgICAgIC8gbWF0aC5mYWN0b3JpYWwobiAtIGsgKyAxKQogICkKCiAgcmV0dXJuIGludChwcmVjZWRpbmcpICsgcmFuayh0YWlsLCBlbGVtZW50cyAtIHtoZWFkfSkKCgpkZWYgdXBkYXRlX3AocCwgaSwgbik6CiAgcFtpXSArPSAxCiAgcHJldiA9IHBbOmldCiAgd2hpbGUgcFtpXSBpbiBwcmV2OgogICAgcFtpXSArPSAxCiAgZm9yIGogaW4gcmFuZ2UoaSArIDEsIGxlbihwKSk6CiAgICBwW2pdID0gMAogICAgcHJldiA9IHBbOmpdCiAgICB3aGlsZSBwW2pdIGluIHByZXY6CiAgICAgIHBbal0gKz0gMQoKCmRlZiB1bnJhbmsoaW5kZXgsIGssIG4pOgogIGVsZW1lbnRzID0gc29ydGVkKHJhbmdlKG4pKQogIHAgPSBlbGVtZW50c1s6a10KICByZW1haW5pbmcgPSBpbmRleAogIGZvciBpIGluIHJhbmdlKGspOgogICAgaWYgcFtpXSA9PSBuIC0gMToKICAgICAgY29udGludWUKICAgIHdoaWxlIFRydWU6CiAgICAgIHIgPSByYW5rKHAsIHNldChlbGVtZW50cykpCiAgICAgIGlmIHIgPiByZW1haW5pbmc6CiAgICAgICAgYnJlYWsKICAgICAgdXBkYXRlX3AocCwgaSwgbikKICAgICAgcHJpbnQoKHAscikpCiAgICAgIGNhbmRpZGF0ZSA9IHJlbWFpbmluZyAtIHIKICAgIHJlbWFpbmluZyA9IGNhbmRpZGF0ZQogIHJldHVybiBwCgpuID0gNAprID0gMgoKZm9yIHAgaW4gc29ydGVkKGl0ZXJ0b29scy5jaGFpbi5mcm9tX2l0ZXJhYmxlKG1hcCgKICAgIGxhbWJkYSB4OiBsaXN0KGl0ZXJ0b29scy5wZXJtdXRhdGlvbnMoeCkpLAogICAgaXRlcnRvb2xzLmNvbWJpbmF0aW9ucyhyYW5nZShuKSwgaykpKSk6CiAgcHJpbnQoKHAsIHJhbmsobGlzdChwKSwgc2V0KHJhbmdlKG4pKSkpKQoKbiA9IDIwNDgKayA9IDI0CnAgPSByYW5kb20uc2FtcGxlKHJhbmdlKG4pLCBrKQojIHByaW50KChwLCByYW5rKHAsIHNldChyYW5nZShuKSkpKSkKCm51bV90ZXN0cyA9IDEKbWF4X24gPSAyMAptYXhfayA9IDUKCmZvciBfIGluIHJhbmdlKG51bV90ZXN0cyk6CiAgbiA9IHJhbmRvbS5yYW5kaW50KDUsIG1heF9uKQogIGsgPSByYW5kb20ucmFuZGludCgyLCBtaW4obWF4X2ssIG4pKQoKICBwID0gcmFuZG9tLnNhbXBsZShyYW5nZShuKSwgaykKICBwLCBrLCBuID0gWzYsIDJdLCAyLCAxNAogIGVsZW1lbnRzID0gc2V0KHJhbmdlKG4pKQogIAogIHJhbmtfcCA9IHJhbmsocCwgZWxlbWVudHMpCiAgdW5yYW5rZWQgPSB1bnJhbmsocmFua19wLCBrLCBuKQoKICBpZiB1bnJhbmtlZCAhPSBwOgogICAgcHJpbnQoKHAsIG4sIHJhbmtfcCwgdW5yYW5rZWQsIHJhbmsodW5yYW5rZWQsIGVsZW1lbnRzKSkpCiAgICBicmVhaw==
((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)