Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions algos/mathematics/combinatorics/lehmer_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from collections import Counter
from functools import reduce
from typing import Final

ELEMENTS: Final = (
"A",
"B",
"C",
"D",
"E",
)
N_PERMUTATIONS: Final = reduce(lambda x, y: x * y, range(len(ELEMENTS), 0, -1))


def rank(permutation: tuple[str, ...]) -> int:
if Counter(permutation) != Counter(ELEMENTS):
raise ValueError("Invalid permutation")

rank = 0
for i, element in enumerate(permutation):
rank += ELEMENTS.index(element) * len(ELEMENTS) ** (len(permutation) - i - 1)
return rank


def unrank(rank: int) -> tuple[str, ...]:
if rank < 0 or rank >= len(ELEMENTS) ** len(ELEMENTS):
raise ValueError("Invalid rank")

permutation = []
for i in range(len(ELEMENTS)):
permutation.append(ELEMENTS[rank % len(ELEMENTS)])
rank //= len(ELEMENTS)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing Return and Incorrect Validation

The unrank function implicitly returns None because it's missing a return statement for the permutation it computes. Additionally, its rank validation incorrectly uses len(ELEMENTS) ** len(ELEMENTS) as the upper bound instead of N_PERMUTATIONS (n!), which is not correct for Lehmer codes.

Fix in Cursor Fix in Web


if __name__ == "__main__":
print(N_PERMUTATIONS)
print(ELEMENTS)
print(
rank(
(
"A",
"B",
"C",
"D",
"E",
)
)
)
print(
unrank(
rank(
(
"A",
"B",
"C",
"D",
"E",
)
)
)
)
print(unrank(1))