Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get permutation with specified degree by index number

I've been working on this for hours but couldn't figure it out.

Define a permutation's degree to be the minimum number of transpositions that need to be composed to create it. So a the degree of (0, 1, 2, 3) is 0, the degree of (0, 1, 3, 2) is 1, the degree of (1, 0, 3, 2) is 2, etc.

Look at the space Snd as the space of all permutations of a sequence of length n that have degree d.

I want two algorithms. One that takes a permutation in that space and assigns it an index number, and another that takes an index number of an item in Snd and retrieves its permutation. The index numbers should obviously be successive (i.e. in the range 0 to len(Snd)-1, with each permutation having a distinct index number.)

I'd like this implemented in O(sane); which means that if you're asking for permutation number 17, the algorithm shouldn't go over all the permutations between 0 and 16 to retrieve your permutation.

Any idea how to solve this?

(If you're going to include code, I prefer Python, thank you.)

Update:

I want a solution in which

  1. The permutations are ordered according to their lexicographic order (and not by manually ordering them, but by an efficient algorithm that gives them with lexicographic order to begin with) and
  2. I want the algorithm to accept a sequence of different degrees as well, so I could say "I want permutation number 78 out of all permutations of degrees 1, 3 or 4 out of the permutation space of range(5)". (Basically the function would take a tuple of degrees.) This'll also affect the reverse function that calculates index from permutation; based on the set of degrees, the index would be different.

I've tried solving this for the last two days and I was not successful. If you could provide Python code, that'd be best.

like image 259
Ram Rachum Avatar asked May 16 '14 15:05

Ram Rachum


People also ask

How do you find the index of a permutation?

Multiply the index of the first digit among the digits in the permutation by (n-1)! and add the index of the remaining permutation. For example, 2 has index 1 , and the index of 13 is 0 , so the result is 1 * (3-1)! + 0 = 1 * 2 = 2 . Save this answer.

How do you generate all permutations of an array?

You take first element of an array (k=0) and exchange it with any element (i) of the array. Then you recursively apply permutation on array starting with second element. This way you get all permutations starting with i-th element.

What is permutation index?

1. The index of a permutation p is defined as the sum of all subscripts j such that p_j>p_(j+1), for 1<=j<=n.

How many permutations are there of a set with n elements?

The number of permutations of n distinct objects is n factorial, usually written as n!, which means the product of all positive integers less than or equal to n. that are considered for studying permutations.


1 Answers

The permutations of length n and degree d are exactly those that can be written as a composition of k = n - d cycles that partition the n elements. The number of such permutations is given by the Stirling numbers of the first kind, written n atop k in square brackets.

Stirling numbers of the first kind satisfy a recurrence relation

[n]           [n - 1]   [n - 1]
[ ] = (n - 1) [     ] + [     ]
[k]           [  k  ]   [k - 1],

which means, intuitively, the number of ways to partition n elements into k cycles is to partition n - 1 non-maximum elements into k cycles and splice in the maximum element in one of n - 1 ways, or put the maximum element in its own cycle and partition the n - 1 non-maximum elements into k - 1 cycles. Working from a table of recurrence values, it's possible to trace the decisions down the line.

memostirling1 = {(0, 0): 1}
def stirling1(n, k):
    if (n, k) not in memostirling1:
        if not (1 <= k <= n): return 0
        memostirling1[(n, k)] = (n - 1) * stirling1(n - 1, k) + stirling1(n - 1, k - 1)
    return memostirling1[(n, k)]

def unrank(n, d, i):
    k = n - d
    assert 0 <= i <= stirling1(n, k)
    if d == 0:
        return list(range(n))
    threshold = stirling1(n - 1, k - 1)
    if i < threshold:
        perm = unrank(n - 1, d, i)
        perm.append(n - 1)
    else:
        (q, r) = divmod(i - threshold, stirling1(n - 1, k))
        perm = unrank(n - 1, d - 1, r)
        perm.append(perm[q])
        perm[q] = n - 1
    return perm
like image 170
David Eisenstat Avatar answered Oct 12 '22 22:10

David Eisenstat