packages feed

sym-0.9: cbits/rank.c

/* (c) Anders Claesson 2013 */

#include <stdlib.h>
#include <string.h>
#include <math.h>


static inline void
swap(long *p1, long *p2)
{
	long tmp;

	tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}


/* Returns the rank-th (Myrvold & Ruskey) permutation of {0..len-1}.
 * E.g., len = 3 and rank = 0..5 gives 120 201 102 210 021 012
 */
void
unrank(long *w, long len, double rank)
{
	register long i;

	for (i = 0; i < len; i++)
		w[i] = i;

	for (i = len; i > 0; i--) {
		swap(w + i - 1, w + (long)fmod(rank, i));
		rank /= i;
	}
}


/* Returns the (Myrvold & Ruskey)-rank of the length len permutation w.
 */
double
rank(long *w, long len)
{
	long s;
	long r = 0;
	long a = 1;
	long size = len * sizeof(*w);
	long *u = alloca(size);
	long *v = alloca(size);
	register long i;

	/* Let v = w */
	memcpy(v, w, size);

	/* Let u = w^{-1} */
	for (i = 0; i < len; i++, w++)
		u[*w] = i;

	while (--len > 0) {
		s = v[len];
		swap(v + len, v + u[len]);
		swap(u + s, u + len);
		r += s*a;
		a *= len+1;
	};

	return r;
}