
#include "perm/rotate.h"
#include "aux0/swap.h"
#include "fxttypes.h"


void
perm2ffact(const ulong *x, ulong n, ulong *fc)
// Convert permutation in x[0,...,n-1] into
//   the (n-1) digit falling factorial representation in fc[0,...,n-2].
// One has: fc[0]<n, fc[1]<n-1, ..., fc[n-2]<2 (falling radices)
// Works as long as all elements in x[] are distinct.
// This is the so-called "Lehmer code" of a permutation.
{
    for (ulong k=0; k<n-1; ++k)
    {
        ulong xk = x[k];
        ulong i = 0;
        for (ulong j=k; j<n; ++j)  if ( x[j]<xk )  ++i;
        fc[k] = i;
    }
}
// -------------------------

void
ffact2perm(const ulong *fc, ulong n, ulong *x)
// Inverse of perm2ffact():
// Convert the (n-1) digit falling factorial representation in fc[0,...,n-2].
// into permutation in x[0,...,n-1]
// Must have: fc[0]<n, fc[1]<n-1, ..., fc[n-2]<2 (falling radices)
{
    for (ulong k=0; k<n; ++k)  x[k] = k;
    for (ulong k=0; k<n-1; ++k)
    {
        ulong fa = fc[k];
        if ( fa )  rotate_right1(x+k, fa+1);
    }
}
// -------------------------

void
ffact2invperm(const ulong *fc, ulong n, ulong *x)
// Convert the (n-1) digit falling factorial representation in fc[0,...,n-2]
// into permutation in x[0,...,n-1] such that
// the permutation is the inverse of the one computed via ffact2perm().
// Must have: fc[0]<n, fc[1]<n-1, ..., fc[n-2]<2 (falling radices)
{
#if 1
    for (ulong k=0; k<n; ++k)  x[k] = k;
    for (ulong k=n-2; (long)k>=0; --k)
    {
        ulong fa = fc[k];
        if ( fa )  rotate_left1(x+k, fa+1);
    }

#else
    for (ulong k=0; k<n; ++k)  x[k] = n-1;  // "empty"
    for (ulong k=0; k<n-1; ++k)
    {
        ulong fa = fc[k];
        for (ulong j=0;  ; ++j)
        {
            if ( x[j]==n-1 )  // if empty
            {
                if ( 0==fa )  { x[j] = k;  break; }
                --fa;
            }
        }
    }
#endif
}
// -------------------------


void
perm2rfact(const ulong *x, ulong n, ulong *fc)
// Convert permutation in x[0,...,n-1] into
//   the (n-1) digit rising factorial representation in fc[0,...,n-2].
// One has: fc[0]<2, fc[1]<3, ..., fc[n-2]<n (rising radices)
// Works as long as all elements in x[] are distinct.
{
    for (ulong k=1; k<n; ++k)
    {
        ulong xk = x[k];
        ulong i = 0;
        for (ulong j=0; j<k; ++j)  if ( x[j]>xk )  ++i;
        fc[k-1] = i;
    }
}
// -------------------------

void
rfact2perm(const ulong *fc, ulong n, ulong *x)
// Inverse of perm2rfact():
// Convert the (n-1) digit rising factorial representation in fc[0,...,n-2].
//  into permutation in x[0,...,n-1]
// Must have: fc[0]<2, fc[1]<3, ..., fc[n-2]<n (rising radices)
{
    for (ulong k=0; k<n; ++k)  x[k] = k;
    ulong *y = x+n;
    for (ulong k=n-1;  k!=0;  --k, --y)
    {
        ulong fa = fc[k-1];
        if ( fa )  { ++fa;  rotate_left1(y-fa, fa); }
    }
}
// -------------------------


void
rfact2invperm(const ulong *fc, ulong n, ulong *x)
// Convert the (n-1) digit rising factorial representation in fc[0,...,n-2].
//  into permutation in x[0,...,n-1] such that
// the permutation is the inverse of the one computed via rfact2perm().
// Must have: fc[0]<2, fc[1]<3, ..., fc[n-2]<n (rising radices)
{
#if 1
    for (ulong k=0; k<n; ++k)  x[k] = k;
    ulong *y = x + 2;
    for (ulong k=0;  k<n-1;  ++k, ++y)
    {
        ulong fa = fc[k];
        if ( fa )  { ++fa;  rotate_right1(y-fa, fa); }
    }

#else
    for (ulong k=0; k<n; ++k)  x[k] = 0;  // "empty"
    for (ulong k=n-2; (long)k>=0; --k)
    {
        ulong fa = fc[k];
        for (ulong j=0;  ; ++j)
        {
            if ( x[j]==0 )  // if empty
            {
                if ( 0==fa )  { x[j] = k+1;  break; }
                --fa;
            }
        }
    }
    // reverse x[]:
    for (ulong k=0, r=n-1;  k<r;  ++k, --r)  swap2(x[k], x[r]);
#endif
}
// -------------------------
