Ranking and unranking combinations with replacement

161 Views Asked by At

Problem statement:

You observe a sample of five 6-sided dice. Compute this sample's rank, then show how to unrank it.


General Overview

The number of combinations with replacement can be calculated as $\frac{(n + r - 1)!}{r!(n - 1)!}$, where $n$ is the number of objects and $r$ is the number of outcomes for each object.

Substituting $n=5$ (dice) and $r=6$ (sides per dice) tells us there are $252$ outcomes in our dice problem.

Definitions (from Lucia Moura's slides on Combinatorial Generation)

  • Let $\mathcal{S}$ be a finite set and $N = |\mathcal{S}|$

  • A rank function is a bijection:

$$ \textit{Rank}: \mathcal{S} \rightarrow \{0, 1, ..., N - 1\} $$

  • And the unrank function is the opposite bijection:

$$ \textit{Unrank}: \{0, 1, ..., N - 1\} \rightarrow \mathcal{S} $$

For example:

$$ \begin{aligned} (1, 1, 1, 1, 1) &\rightarrow 0 \\ (1, 1, 1, 1, 2) &\rightarrow 1 \\ ... \\ (2, 2, 4, 6, 6) &\rightarrow 156 \\ ... \\ (5, 6, 6, 6, 6) &\rightarrow 250 \\ (6, 6, 6, 6, 6) &\rightarrow 251 \\ \end{aligned} $$


Reading + What I've tried

I was reading the Wikipedia page on Combinatorial Number Systems and the slides above, but all the examples for ranking and unranking seem to be based on combinations without replacement.

For small cases (such as the one in the problem statement) it's easy to enumerate, here's an example with Python I used to construct the example above. Enumeration gets problematic for large $n$ and $r$ though, e.g. if we play with 50 dice then $|\mathcal{S}| = 3,478,761$.

from itertools import combinations_with_replacement

for i, sample in enumerate(combinations_with_replacement(range(1, 7), 5)):
  print(i, sample)

There might be a simple solution if the samples are interpreted in a different base, then adding corresponding positions. If we subtract 1 from all entries, then the ranking problem looks like this:

$$ \begin{aligned} (0, 0, 0, 0, 0) &\rightarrow 0 \\ (0, 0, 0, 0, 1) &\rightarrow 1 \\ (0, 0, 0, 0, 2) &\rightarrow 2 \\ ... \\ (1, 1, 3, 5, 5) &\rightarrow 156 \\ ... \\ (4, 5, 5, 5, 5) &\rightarrow 250 \\ (5, 5, 5, 5, 5) &\rightarrow 251 \\ \end{aligned} $$

... but I haven't found a general solution yet.