From: Thad Smith on
Mok-Kong Shen wrote:
>
> Permutations of n different objects can be ordered and thus mapped to
> numbers. There are good algorithms for doing the conversions. See
>
> http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
>
>
> If there are only two kinds of objects (say, black and white), with n
> even and n/2 objects of each kind, are there good algorithms of doing
> the same?

I wrote some code for this a while back. I don't recall the technique,
but I'll look for code and give a detailed reply later.

It was a very general routine that lets the caller specify the number of
elements for each distinct item, plus the minimum and maximum number of
elements in the set of permutations (for example: 3 A's, 2 B's, 5 C's,
all permutations with 6 to 10 elements). It then maps an index to a
permutation or vice-versa.

--
Thad
From: Gene on
On Jan 3, 12:23 pm, Patricia Shanahan <p...(a)acm.org> wrote:
> Mok-Kong Shen wrote:
>
> > Permutations of n different objects can be ordered and thus mapped to
> > numbers. There are good algorithms for doing the conversions. See
>
> >http://stackoverflow.com/questions/1506078/fast-permutation-number-pe...
>
> > If there are only two kinds of objects (say, black and white), with n
> > even and n/2 objects of each kind, are there good algorithms of doing
> > the same?
>
> This is equivalent to the problem of specifying a set of n/2 unique
> numbers each in the range from 1 through n. Regard the selected set as
> the index values for the black elements. Any index not in the set gets a
> white element.
>
> There are n choices for the first number, n-1 choices for the second
> one, ..., 1+n/2 choices for the last of the n/2 selected numbers.
>
> Patricia

Yes! Except that I think after you've made the first choice, say it's
k_1, then the next choice must be k_2 in[1..k_1), then k_3 in [1..k_2)
and so forth. Otherwise there's more than one way to get each
combination, which is what we're really computing an ordering on, just
as you say: n choose n/2.



From: Thad Smith on
Mok-Kong Shen wrote:
>
> Permutations of n different objects can be ordered and thus mapped to
> numbers. There are good algorithms for doing the conversions. See
>
> http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
>
>
> If there are only two kinds of objects (say, black and white), with n
> even and n/2 objects of each kind, are there good algorithms of doing
> the same?

Here is C code to compute a permutation from an index and the number of each
unique element, along with a test driver. For example
permx 3 2 4
computes permutation 3 using 2 1's and 4 2's. The permutations are in lexical
order, with permutation 0 being the lowest value.

You could extend the range by using unsigned long long or other extended integer
type.


/* PERMX.C - Compute permutation index from permutation and inverse.
**
** These routines compute a permutation index from a given full permutation
** using all elements of a multi-set (duplicate items allowed).
**
** 031130 Thad Smith - original version.
*/

#include <stdlib.h>

typedef unsigned char tElem; /* element value for permutation, 0..max */
typedef unsigned long tPermX; /* permutation index, 0..max */

/* Function: XtoPerm
** Description: This function computes the permutation from a permutation
** index. The permutations are in lexical order.
** On entry:
** On exit: return value = status (see return comment)
** ret=0: perm[] contains permutation.
*/
int /* 0=perm returned, 1=index out of range,
** 2=overflow, 3=telems mismatch */
XtoPerm (
tElem perm[], /* resulting permutation [0..telems-1] */
tPermX permx, /* permutation index */
size_t nelems, /* number of unique elements in set */
size_t telems, /* total number of elements in set */
int elemCount[] /* elemCount[i] = number of copies of elements i
** in the set, i=0..nelems-1 */
) {
tPermX tnp; /* total number of permutations */
tPermX ntnp; /* temp px */
tPermX lcc; /* number of permutations for remaining elements
** after item i chosen */
tPermX plcc; /* prev value of lcc */
int te; /* total number of elements */
int c; /* single element count */
int r; /* return code */
int i, j; /* temp */

/* compute total number of permutations */
tnp = 1;
te = 0;
for (i=0; i < nelems; i++) {
c = elemCount[i];
for (j=1; j <= c; j++) {
te++;
ntnp = tnp * te;
if (ntnp/te < tnp) return 2; /* overflow */
tnp = ntnp / j;
}
}
if (te != telems) return 3; /* count mismatch */
if (permx >= tnp) return 1; /* index too high */

/* Find the first element */
plcc = lcc = 0;
for (i=0; i < nelems; i++) {
c = elemCount[i];
if (c == 0) continue;
lcc += (double)tnp*c/telems;
if (lcc > permx) {
/* assign first element */
elemCount[i]--;
perm[0] = i;
r = XtoPerm (perm+1,permx-plcc,nelems,telems-1,elemCount);
elemCount[i]++;
return r;
}
plcc = lcc;
}
return 0;
}

#include <stdio.h>

int main (int argc, char *argv[]) {
int nelems, telems;
tPermX px; /* specified perm index */
int i;
int s; /* return status */
int count[20];
tElem perm[100]; /* permutation */

if (argc > 3 && argc < 22) {
px = atol (argv[1]);
nelems = argc-2;
telems = 0;
for (i=0; i < argc-2; i++) {
count[i] = atoi (argv[i+2]);
if (count[i] <= 0) goto help;
telems += count[i];
if (telems > sizeof perm / sizeof (perm[0])) goto help;
}
s = XtoPerm (perm, px, nelems, telems, count);
printf ("stat=%d, perm:", s);
for (i=0; i < telems; i++) {
printf ("%d ", (int)perm[i]+1);
}
printf ("\n");
} else {
help:
printf ("Use: permx index n1 n2 ... nn\n"
" permx = index of permutation\n"
" nx = number of copies of item x in set\n");
return 1;
}
return 0;
}


--
Thad
From: Mok-Kong Shen on
Thad Smith wrote:

> Here is C code to compute a permutation from an index and the number of
> each unique element, along with a test driver. For example
> permx 3 2 4
> computes permutation 3 using 2 1's and 4 2's. The permutations are in
> lexical order, with permutation 0 being the lowest value.
[snip]

I have tried your code. It's excellent. I also need however the
code for conversion from a permutation to its index. Please be
kind enough to supply it too.

Thanks in advance.

M. K. Shen
From: Gene on
On Jan 4, 11:34 pm, Thad Smith <ThadSm...(a)acm.org> wrote:
> Mok-Kong Shen wrote:
>
> > Permutations of n different objects can be ordered and thus mapped to
> > numbers. There are good algorithms for doing the conversions. See
>
> >http://stackoverflow.com/questions/1506078/fast-permutation-number-pe...
>
> > If there are only two kinds of objects (say, black and white), with n
> > even and n/2 objects of each kind, are there good algorithms of doing
> > the same?
>
> Here is C code to compute a permutation from an index and the number of each
> unique element, along with a test driver.  For example
> permx 3 2 4
> computes permutation 3 using 2 1's and 4 2's.  The permutations are in lexical
> order, with permutation 0 being the lowest value.
>
> You could extend the range by using unsigned long long or other extended integer
> type.
>
> /* PERMX.C - Compute permutation index from permutation and inverse.
> **
> ** These routines compute a permutation index from a given full permutation
> ** using all elements of a multi-set (duplicate items allowed).
> **
> ** 031130 Thad Smith - original version.
> */
>
> #include <stdlib.h>
>
> typedef unsigned char tElem;    /* element value for permutation, 0..max */
> typedef unsigned long tPermX;   /* permutation index, 0..max */
>
> /* Function:    XtoPerm
> ** Description: This function computes the permutation from a permutation
> **              index.  The permutations are in lexical order.
> ** On entry:
> ** On exit:     return value = status (see return comment)
> **              ret=0: perm[] contains permutation.
> */
> int                     /* 0=perm returned, 1=index out of range,
>                          ** 2=overflow,      3=telems mismatch   */
> XtoPerm (
>      tElem   perm[],     /* resulting permutation [0..telems-1] */
>      tPermX  permx,      /* permutation index */
>      size_t  nelems,     /* number of unique elements in set */
>      size_t  telems,     /* total number of elements in set */
>      int elemCount[]     /* elemCount[i] = number of copies of elements i
>                          ** in the set, i=0..nelems-1                    */
> ) {
>      tPermX  tnp;        /* total number of permutations */
>      tPermX  ntnp;       /* temp px */
>      tPermX  lcc;        /* number of permutations for remaining elements
>                          ** after item i chosen          */
>      tPermX  plcc;       /* prev value of lcc */
>      int     te;         /* total number of elements */
>      int     c;          /* single element count */
>      int     r;          /* return code */
>      int     i, j;       /* temp */
>
>      /* compute total number of permutations */
>      tnp = 1;
>      te = 0;
>      for (i=0; i < nelems; i++) {
>          c = elemCount[i];
>          for (j=1; j <= c; j++) {
>              te++;
>              ntnp = tnp * te;
>              if (ntnp/te < tnp) return 2;       /* overflow */
>              tnp = ntnp / j;
>          }
>      }
>      if (te != telems) return 3;     /* count mismatch */
>      if (permx >= tnp)   return 1;   /* index too high */
>
>      /* Find the first element */
>      plcc = lcc = 0;
>      for (i=0; i < nelems; i++) {
>          c = elemCount[i];
>          if (c == 0) continue;
>          lcc += (double)tnp*c/telems;
>          if (lcc > permx) {
>              /* assign first element */
>              elemCount[i]--;
>              perm[0] = i;
>              r = XtoPerm (perm+1,permx-plcc,nelems,telems-1,elemCount);
>              elemCount[i]++;
>              return r;
>          }
>          plcc = lcc;
>      }
>      return 0;
>
> }
>
> #include <stdio.h>
>
> int main (int argc, char *argv[]) {
>      int nelems, telems;
>      tPermX px;              /* specified perm index */
>      int i;
>      int s;                  /* return status */
>      int count[20];
>      tElem perm[100];        /* permutation */
>
>      if (argc > 3 && argc < 22) {
>          px = atol (argv[1]);
>          nelems = argc-2;
>          telems = 0;
>          for (i=0; i < argc-2; i++) {
>              count[i] = atoi (argv[i+2]);
>              if (count[i] <= 0) goto help;
>              telems += count[i];
>              if (telems > sizeof perm / sizeof (perm[0])) goto help;
>          }
>          s = XtoPerm (perm, px, nelems, telems, count);
>          printf ("stat=%d, perm:", s);
>          for (i=0; i < telems; i++) {
>              printf ("%d ", (int)perm[i]+1);
>          }
>          printf ("\n");
>      } else {
> help:
>          printf ("Use: permx index n1 n2 ... nn\n"
>          "  permx = index of permutation\n"
>          "  nx = number of copies of item x in set\n");
>          return 1;
>      }
>      return 0;
>
> }

This is a nice piece of work. Thanks for sharing it.