// -*- C++ -*-
// automatically generated by autodoc

// ========== HEADER FILE src/perm/even2lower.h: ==========

inline void even2lower(Type *f, ulong n);
// With the input (comma at middle of array):
//   [e0 o0 e1 o1 e2 o3 ..., E0 O0 E1 O1 E2 O2 ... ]
// obtain:
//   [e0 E0 e1 E1 e2 E3 ..., o0 O0 o1 O1 o2 O2 ... ]
// Self-inverse.
// n must be even.

inline void even2lower_rev(Type *f, ulong n);
// Similar to even2lower() but the order of the swapped elements is reversed.
// Self-inverse.
// n must be even.

inline void odd2lower(Type *f, ulong n);
// With the input (comma at middle of array):
//   [e0 o0 e1 o1 e2 o3 ..., E0 O0 E1 O1 E2 O2 ... ]
// obtain:
//   [O0 o0 O1 o1 O2 o3 ..., E0 e0 E1 e1 E2 e2 ... ]
// Self-inverse.
// n must be even.

// ========== HEADER FILE src/perm/fact2perm-swp-apply.h: ==========

void ffact2perm_swp_apply(const ulong *fc, ulong n, Type *x);
// Permute x by permutation corresponding to ffact2perm_swp().

void ffact2invperm_swp_apply(const ulong *fc, ulong n, Type *x);
// Permute x by permutation corresponding to ffact2invperm_swp().

void rfact2perm_swp_apply(const ulong *fc, ulong n, Type *x);
// Permute x by permutation corresponding to rfact2perm_swp().

void rfact2invperm_swp_apply(const ulong *fc, ulong n, Type *x);
// Permute x by permutation corresponding to rfact2invperm_swp().

// ========== HEADER FILE src/perm/graypermute.h: ==========

inline void gray_permute(const Type *f, Type * restrict g, ulong n);
// Put Gray permutation of f[] to g[], i.e. g[gray_code(k)] == f[k]

inline void inverse_gray_permute(const Type *f, Type * restrict g, ulong n);
// Put inverse Gray permutation of f[] to g[], i.e. g[k] == f[gray_code(k)]
// (same as: g[inverse_gray_code(k)] == f[k])

void gray_permute(Type *f, ulong n);
// Gray permutation, in-place version
// the only difference to inverse_gray_permute()
//  is the 'do cycle' block

void inverse_gray_permute(Type *f, ulong n);
// Inverse Gray permutation, in-place version
// the only difference to gray_permute()
//  is the 'do cycle' block

// ========== HEADER FILE src/perm/grayrevpermute.h: ==========

inline void gray_rev_permute(const Type *f, Type * restrict g, ulong n);
// gray_rev_permute() =^=
//  { reverse(); gray_permute(); }

inline void inverse_gray_rev_permute(const Type *f, Type * restrict g, ulong n);
// inverse of gray_rev_permute()
// inverse_gray_rev_permute() =^=
//  { inverse_gray_permute(); reverse(); }

void gray_rev_permute(Type *f, ulong n);
// n must be a power of 2, n<=2**(BITS_PER_LONG-2)

void inverse_gray_rev_permute(Type *f, ulong n);
// n must be a power of 2, n<=BITS_PER_LONG-2

// ========== HEADER FILE src/perm/haarpermute.h: ==========

void haar_permute(Type *f, ulong n);
// Reorder autoput of inplace_haar() as in haar()
// To be called after inplace_haar()

void inverse_haar_permute(Type *f, ulong n);
// Reorder autoput of inverse_inplace_haar() as in inverse_haar()
// To be called before inverse_inplace_haar()

// ========== HEADER FILE src/perm/mrotate.h: ==========

void mrotate(const Type * restrict f, ulong n, ulong r, Type * restrict g);
// for all i:  g[(i*r)%n] <- f[i]
// must have:  gcd(n,r)==1
//
// mrotate(f,n,1,g) =^= { acopy(f,g,n); }
// mrotate(f,n,n-1,g) =^= { acopy(f,g,n); reverse_0(g,n); }

void inverse_mrotate(const Type * restrict f, ulong n, ulong r, Type * restrict g);
// for all i:  g[i] <- f[(i*r)%n]
// must have:  gcd(n,r)==1
//
// inverse of mrotate(), i.e. the following is the identity on y[]:
// { acopy(y, x, n); mrotate(x, n, r, y); acopy(y, x, n); inverse_mrotate(x, n, r, y); }

ulong test_mrotate_eq(const Type *f, ulong n, ulong r, const Type *g);
// test whether:  for all i:  g[(i*r)%n] == f[i]
// Return zero if condition holds.

ulong test_inverse_mrotate_eq(const Type *f, ulong n, ulong r, const Type *g);
// test whether:  for all i:  g[i] == f[(i*r)%n]
// Return zero if condition holds.

// ========== HEADER FILE src/perm/perm2ccf.h: ==========

// ----- SRCFILE=src/perm/perm2ccf.cc: -----
void perm2ccf(const ulong *p, ulong n, ulong *c, bitarray *tb/*=0*/);
// Convert permutation in p[] (array form) into
// canonical cycle form (CCF), written to c[].

void ccf2perm(const ulong *c, ulong n, ulong *p, bitarray *tb/*=0*/);
// Convert permutation in canonical cycle form (CCF) in c[] into
// array form, written to p[].

void print_ccf(const char *bla, const ulong *c, ulong n, bitarray *tb/*=0*/);
// Print cycles of c[], interpreted as canonical cycle form (CCF).

// ========== HEADER FILE src/perm/permapply.h: ==========

void apply_permutation(const ulong *x, const Type *f, Type * restrict g, ulong n);
// Apply the permutation x[] to the array f[],
// i.e. set g[x[k]] <-- f[k]  for all k

void apply_permutation(const ulong *x, Type * restrict f, ulong n, bitarray *bp=0);
// Apply the permutation x[] to the array f[]
// i.e. set f[x[k]] <-- f[k]  for all k
// In-place version.

void apply_inverse_permutation(const ulong *x, const Type *f, Type * restrict g, ulong n);
// Apply the inverse permutation of x[] to the array f[]
// i.e. set g[k] <-- f[x[k]]  for all k
//
// E.g. after
// idx_quick_sort(f, n, x);  apply(x, f, g, n);
//  g[] == sorted( f[] )
//.
// If  f[] is a permutation, then after sort_idx()
// x[] is its inverse and
// idx_quick_sort(f, n, x);  apply_inverse_permutation(f, x, g, n);
// (note that x, f are swapped in apply_inverse_permutation())
//  will make x[] == sorted( f[] )
// ... i.e.  x * f == f * x
//

void apply_inverse_permutation(const ulong *x, Type * restrict f, ulong n, bitarray *bp=0);
// Apply the inverse permutation of x[] to the array f[]
// i.e. set f[k] <-- f[x[k]]  for all k
// In-place version.

// ========== HEADER FILE src/perm/permapplyfunc.h: ==========

void apply_permutation(ulong (*x)(ulong), const Type *f, Type * restrict g, ulong n);
// Set g[x(k)] <-- f[k]  for all k
// Must have:  0<=x(k)<n for all k
//
// Example: The following two lines result in identical g[]:
//    apply_permutation(gray_code, f, g, n);
//    gray_permute(f, g, n);

void apply_permutation(ulong (*x)(ulong), Type * restrict f, ulong n, bitarray *bp=0);
// Set f[x(k)] <-- f[k]  for all k
// Must have:  0<=x(k)<n for all k
// In-place version.

void apply_inverse_permutation(ulong (*x)(ulong), const Type *f, Type * restrict g, ulong n);
// Set g[k] <-- f[x(k)]  for all k
// Must have:  0<=x(k)<n for all k, and x(i)!=x(j) for all i!=j

void apply_inverse_permutation(ulong (*x)(ulong), Type *f, ulong n, bitarray *bp=0);
// Set f[k] <-- f[x(k)]  for all k
// Must have:  0<=x(k)<n for all k, and x(i)!=x(j) for all i!=j
// In-place version.

// ========== HEADER FILE src/perm/permcomplement.h: ==========

inline void make_complement(const ulong *f, ulong *g, ulong n);
// Set (as permutation) g to the complement of f.
// Can have f==g.

inline void make_complement(ulong *f, ulong n);
// Set (as permutation) f to its complement.

// ========== HEADER FILE src/perm/permcompose.h: ==========

// ----- SRCFILE=src/perm/permcompose.cc: -----
void make_square(const ulong *f, ulong * restrict g, ulong n);
// Set (as permutation) g = f * f

void make_square(ulong *f, ulong n, bitarray *bp/*=0*/);
// Set (as permutation) f = f * f
// In-place version.

void compose(const ulong *f, const ulong *g, ulong * restrict h, ulong n);
// Set (as permutation) h = f * g

void compose(const ulong *f, ulong * restrict g, ulong n);
// Set (as permutation) g = f * g

void power(const ulong *f, ulong * restrict g, ulong n,
      long e,
      ulong * restrict t/*=0*/);
// Set (as permutation) g = f ** e

// ========== HEADER FILE src/perm/perminvert.h: ==========

// ----- SRCFILE=src/perm/perminvert.cc: -----
void make_inverse(const ulong *f, ulong * restrict g, ulong n);
// Set (as permutation) g to the inverse of f

void make_inverse(ulong *f, ulong n, bitarray *bp/*=0*/);
// Set (as permutation) f to its own inverse.
// In-place version.

void boothroyd_invert(ulong *f, ulong n, bitarray *bp/*=0*/);
// Set f to its own inverse. Boothroyd's algorithm.
// Complexity is n*log(n), so make_inverse() is faster.
// Knuth says the algorithm is ingenious, so its here.
// In-place version.

// ========== HEADER FILE src/perm/permq.h: ==========

// ----- SRCFILE=src/perm/permq.cc: -----
bool is_identity(const ulong *f, ulong n);
// Return whether f[] is the identical permutation,
// i.e. whether f[k]==k for all k= 0...n-1

bool has_fixed_points(const ulong *f, ulong n);
// Return whether f[k]==k for any k= 0...n-1

ulong count_fixed_points(const ulong *f, ulong n);
// Return number of fixed points in f[]

ulong count_descents(const ulong *f, ulong n);
// Return number of descents in f[]

ulong count_excedances(const ulong *f, ulong n, bool eq/*=true*/);
// Return number of excedances in f[]:
// an excedance is a position k where f[k]>k.
// If eq==false then return number of k such that f[k]<k

ulong count_inversions(const ulong *f, ulong n);
// Return number of inversions in f[],
// i.e. number of pairs k,j where k<j and f[k]>f[j]
// Work is n*n

ulong count_inversions(const ulong *f, ulong n, left_right_array *tLR);
// Return number of inversions in f[],
// i.e. number of pairs k,j where k<j and f[k]>f[j]
// Version for large arrays, work is n*log_2(n)

bool is_derangement(const ulong *f, ulong n);
// Return whether f[] is a derangement of identity,
// i.e. whether f[k]!=k for all k

bool is_derangement(const ulong *f, const ulong *g, ulong n);
// Return whether f[] is a derangement of g[],
// i.e. whether f[k]!=g[k] for all k

bool is_connected(const ulong *f, ulong n);
// Return whether permutation is connected (indecomposable),
// i.e. whether {f[0],f[1],...,f[k]} != {0,...,k} for all k<n-1
// i.e. whether no proper prefix of the array is mapped to itself.

bool is_updown_permutation(const ulong *f, ulong n);
// Return whether f is an up-down condition,
// i.e. whether f[0] < f[1] > f[2] < f[3] > ...

bool is_cyclic(const ulong *f, ulong n);
// Return whether permutation is exactly one cycle.

bool is_valid_permutation(const ulong *f, ulong n, bitarray *bp/*=0*/);
// Return whether all values 0...n-1 appear exactly once,
// i.e. whether f represents a permutation of [0,1,...,n-1].

bool is_involution(const ulong *f, ulong n, bool hint/*=false*/);
// Return whether max cycle length is <= 2,
// i.e. whether f * f = id.
// Set hint to true if the permutation is expected to be
// an involution

bool is_inverse(const ulong *f, const ulong *g, ulong n, bool hint/*=false*/);
// Return whether f[] is the inverse of g[].
// Set hint to true if the permutations are expected to be
// mutual inverses.

bool is_square(const ulong *f, const ulong *g, ulong n);
// Return whether f * f == g  as a permutation

ulong get_index(const ulong *f, ulong n);
// Return index of permutation.

ulong count_transpositions(const ulong *f, ulong n, bitarray *bp/*=0*/);
// Return minimal number of transpositions required for the permutation.
// The lowest bit of the return value is the parity of the permutation.

ulong count_cycles(const ulong *f, ulong n, bitarray *bp/*=0*/);

// functions for the application of permutations to data
// are found in perm/permapply.h
// functions for random permutations
// are found in perm/permrand.h
// ========== HEADER FILE src/perm/permrand-2cycles.h: ==========

inline void init_harmonic(double *b, ulong n);
// Set  b[k] = sum( j=1, k+1, 1/j )

inline void random_permute_2cycles(Type *f, ulong n,;
                                   double *tb=0, bool bi=false)
// Permute the elements of f by a random permutation
//   consisting of exactly two cycles (must have n>1).
// Set bi:=true to signal that the sums tb[k] = sum( j=1, k+1, 1/j )
//   have been precomputed (via init_harmonic()).

inline void random_2cycles_permutation(Type *f, ulong n,;
                                       double *tb=0, bool bi=false)

// ========== HEADER FILE src/perm/permrand-connected.h: ==========

inline void random_connected_permutation(ulong *f, ulong n);
// Create a random connected (indecomposable) permutation.

// ========== HEADER FILE src/perm/permrand-cycle-type.h: ==========

inline ulong random_cycle(Type *f, ulong cl, ulong *r, ulong nr);
// Permute a random subset (of size cl)
// of those elements in f whose positions are given in
// r[0], ..., r[nr-1] by a random cycle of size cl.
// Must have  nr >= cl  and  cl != 0.
// Complexity O(cl).

inline void random_permute_cycle_type(Type *f, ulong n, const ulong *c,;
                                      ulong *tr=0)
// Permute the elements of f by a random permutation of prescribed cycle type.
// The permutation will have c[k] cycles of length k+1.
// Must have s <= n where s := sum(k=0, n-1, c[k]).
// If s < n then the permutation will have n-s fixed points.
// Complexity O(n).

inline void random_cycle_type_permutation(ulong *p, ulong n, const ulong *c,;
                                          ulong *tr=0)
// Create a random permutation with prescribed cycle type.
// Complexity O(n).

inline void random_permute_cycle_type(Type *f, ulong n,;
                                      const ulong *m, ulong nm,
                                      const ulong *len,
                                      ulong *tr=0)
// Permute the elements of f by a random permutation of
// prescribed cycle type given as partition:
// The permutation will have m[k] cycles of length len[k]
// where k = 0,1,...,nm-1.
// Must have s <= n where s := sum(k=0, nm-1, m[k]*len[k]).
// If s < n then the permutation will have n-s fixed points.
// Complexity O(n).

inline void random_cycle_type_permutation(ulong *p, ulong n,;
                                          const ulong *m, ulong nm,
                                          const ulong *len,
                                          ulong *tr=0)
// Create a random permutation with prescribed cycle type.
// Complexity O(n).

// ========== HEADER FILE src/perm/permrand-cyclic.h: ==========

void random_permute_cyclic(Type *f, ulong n);
// Permute the elements of f by a random cyclic permutation.

inline void random_cyclic_permutation(ulong *f, ulong n);
// Create a random permutation that is cyclic.

void random_permute_positions_cyclic(Type *f, ulong np, const ulong *ps);
// Randomly permute the np elements f[ps[0]], f[ps[1], ..., f[ps[np-1]]
// by a cyclic permutation.

// ========== HEADER FILE src/perm/permrand-derange.h: ==========

inline void init_derange_branch_ratios(double *b);
// Precompute branching probabilities for random derangements.
//   n ==  1, 2, 3,  4,      5,      6,      7,      8, ...
// b[] ==  0, 1, 0, 0.3333, 0.1818, 0.1698, 0.1423, 0.1250, ...
// b[n-1] == (n-1) * D(n-2) / D(n)

inline double derange_branch_ratio(const double *b, ulong n);
// Reurn probability for closing cycle with n elements.

inline void random_derange(Type *f, ulong n,;
                           ulong *tr=0,
                           double *tb=0, bool bi=false)
// Permute the elements of f by a random derangement.
// Set bi:=true to signal that the branch probabilities in tb[]
//   have been precomputed (via init_derange_branch_ratios()).
// Must have n > 1.

inline void random_derangement(ulong *f, ulong n,;
                               ulong *tr=0,
                               double *tb=0, bool bi=false)
// Create a random permutation that has no fixed points (a derangement).

// ========== HEADER FILE src/perm/permrand-derange3.h: ==========

inline void init_derange3_branch_ratios(double *b, ulong N);
// Precompute branching probabilities for random derangements
//  with all cycles of length >= 3.
//   n ==  2, 3, 4,  5,   6,     7,      8,     9,
//         0, 0, 1,  1,  3/4,  16/19,  95/107, 321/361,
// b[] == [0, 0, 1,  1,  0.75, 0.8421, 0.8878,  0.8891,
// b[n-2] == (n-1) * D3(n-1) / D3(n)  (i.e. offset=2)

inline void random_derange3(Type *f, ulong n,;
                            ulong *tr=0,
                            double *tb=0, bool bi=false)
// Permute the elements of f by a random derangement
//  with all cycles of length >= 3.
// Set bi:=true to signal that the branch probabilities in tb[]
//   have been precomputed (via init_derange3_branch_ratios()).
// Must have n >= 3.

inline void random_derangement3(ulong *f, ulong n,;
                                ulong *tr=0,
                                double *tb=0, bool bi=false)
// Create a random derangement with all cycle lengthes >=3.

// ========== HEADER FILE src/perm/permrand-inv-mod-m.h: ==========

inline void perm_fix_inv_mod(ulong *x, ulong n,;
                             ulong r, ulong m,
                             ulong *tfc=0)
// Adjust permutation x[] such that (i%m)==r
// where i is the number of inversions.
// Must have: 2 <= m <= n  and  0 <= r < m.

inline void random_inv_mod_m_permutation(ulong *p, ulong n,;
                                         ulong r, ulong m,
                                         ulong *tfc=0)
// Create random permutation p[] such that (i%m)==r
// where i is the number of inversions.
// Must have: 2 <= m <= n  and  0 <= r < m.

// ========== HEADER FILE src/perm/permrand-ncm2.h: ==========

void random_permute_ncm2(Type *x, ulong n, ulong r, ulong *tf=0);
// Apply random permutation with number of cycles == r mod 2
// ncm2 := Number of Cycles Modulo 2
// Must have n>=2.

inline void random_ncm2_permutation(ulong *p, ulong n, ulong r, ulong *tf=0);
// Generate a random permutation with number of cycles == r mod 2
// ncm2 := Number of Cycles Modulo 2
// Must have n>=2.

// ========== HEADER FILE src/perm/permrand-ord.h: ==========

inline void random_ord01_permutation(ulong *p, ulong n);
// Random permutation such that elements 0 and 1 are in order.

inline void random_ordk_permutation(ulong *p, ulong n, ulong k);
// Random permutation such that the k smallest elements are in order.
// Must have k<=n.

inline void random_lastk_permutation(ulong *p, ulong n, ulong k);
// Random permutation such that 0 appears as last of the k smallest elements.
// Must have k<=n.

// ========== HEADER FILE src/perm/permrand-parity.h: ==========

void random_permute_parity(Type *f, ulong n, bool par);
// Randomly permute the elements of f, such that the
// parity of the permutation equals par.
// I.e. the minimal number of transpositions of the
//  permutation is even if par==0, else odd.
// Note: with n<=1 there is no odd permutation.

inline void random_parity_permutation(ulong *f, ulong n, bool par);
// Create a random permutation.

// ========== HEADER FILE src/perm/permrand-pref.h: ==========

void random_permute_pref(Type *f, ulong n, ulong m);
// Set the first m elements to a prefix of a random permutation.
// Same as: set the first m elements of f to a random permutation
// of a random selection of all n elements.
// Must have m<=n-1.
// Same as random_permute() if m>=n-1.

inline void random_pref_permutation(ulong *f, ulong n, ulong m);
// Create a length-m random permutation
// of a random selection of m form all n elements.
// Must have m<=n.
// Same as random_permutation() if m>=n-1.

// ========== HEADER FILE src/perm/permrand-sdc.h: ==========

inline void random_sdc_permutation(ulong *p, ulong n,;
                                   const ulong *d, ulong nd,
                                   ulong *tv=0)
// sdc := Sets into Distinct Cycles.
//
// Let NN={0,1,...,n-1},
// S0 be the set of the d[0] smallest elements of NN,
// S1 be the set of the d[1] smallest elements of NN \ S0
// S2 be the set of the d[2] smallest elements of NN \ { S0 union S1 }
// and so on.
// Let m0 = min(S0), m1 = min(S1) etc.,
// write a<<b for "a precedes b".
//
// Generate random permutation such that
//  x << m0 for all elements (!=m0) of S0,
//  m0 << x << m1 for all elements (!=m1) of S1,
//  m1 << x << m2 for all elements (!=m2) of S2,
// and so on.
//
// As canonical cycle form (CCF):
//  The elements of S0 are in one cycle C0,
//  the elements of S1 are in one cycle C1!=C0,
//  the elements of S2 are in one cycle C2!=C1, C2!=C0,
// and so on.

// ========== HEADER FILE src/perm/permrand-self-inverse.h: ==========

inline void next_involution_branch_ratio(double &rat, double &n1);
// R(n) = 1 / ( 1 + (n-1) * R(n-1) )
// R(n+1) = 1 / ( 1 + n * R(n) )

inline void init_involution_branch_ratios(double *b, ulong n);

inline void random_permute_self_inverse(Type *f, ulong n,;
                                        ulong *tr=0,
                                        double *tb=0, bool bi=false)
// Permute the elements of f by a random self-inverse permutation (an involution).
// Set bi:=true to signal that the branch probabilities in tb[]
//   have been precomputed (via init_involution_branch_ratios()).

inline void random_self_inverse_permutation(ulong *f, ulong n,;
                                            ulong *tr=0,
                                            double *tb=0, bool bi=false)
// Create a random permutation that is self-inverse (an involution).

inline ulong rand_num_2cycles_involution(ulong n);
// Return number of 2-cycles for a random involution of n elements.

inline void random_permute_self_inverse1(Type *f, ulong n, ulong *tr=0);
// Permute the elements of f by a random involution.
// This routine avoids the array of branch probabilities.

inline void random_self_inverse_permutation1(ulong *f, ulong n, ulong *tr=0);
// Create a random involution.
// This routine avoids the array of branch probabilities.

// ========== HEADER FILE src/perm/permrand.h: ==========

void random_permute(Type *f, ulong n);
// Randomly permute the elements of f[].

inline void random_permutation(ulong *f, ulong n);
// Create a random permutation.

void random_permute_positions(Type *f, ulong np, const ulong *ps);
// Randomly permute the np elements f[ps[0]], f[ps[1], ..., f[ps[np-1]].

// ========== HEADER FILE src/perm/printcycles.h: ==========

// ----- SRCFILE=src/perm/printcycles.cc: -----
void print_cycles(const ulong *f, ulong n, bitarray *tb/*=0*/);
// Print cycle form of the permutation in f[].
// Examples (first permutations of 4 elements in lex order):
//       array form      cycle form
//   0:  [ 0 1 2 3 ]    (0) (1) (2) (3)
//   1:  [ 0 1 3 2 ]    (0) (1) (2, 3)
//   2:  [ 0 2 1 3 ]    (0) (1, 2) (3)
//   3:  [ 0 2 3 1 ]    (0) (1, 2, 3)
//   4:  [ 0 3 1 2 ]    (0) (1, 3, 2)
//   5:  [ 0 3 2 1 ]    (0) (1, 3) (2)
//   6:  [ 1 0 2 3 ]    (0, 1) (2) (3)
//   7:  [ 1 0 3 2 ]    (0, 1) (2, 3)
//   8:  [ 1 2 0 3 ]    (0, 1, 2) (3)

void print_cycles_len(const ulong *f, ulong n, bitarray *tb/*=0*/);
// Print cycle form of the permutation in f[],
// each cycle on own line.
// For examples, with the permutation
// [ 0 2 4 6 1 3 5 7 ]
// we print:
// (0) #=1
// (1, 2, 4) #=3
// (3, 6, 5) #=3
// (7) #=1

ulong print_cycle(const ulong *f, ulong e0/*=0*/);
// Print the cycle that contains e0.
// Return length of the cycle.

void print_inv_perm_code(const char *bla, const ulong *f, ulong n, bitarray *tb/*=0*/);
// Print code for the inverse permutation in f[],
// For examples, the permutation
//  x[] = [ 0 2 4 6 1 3 5 7 ]
// maps identity to (the inverse of x[]):
//  f[] = [ 0 4 1 5 2 6 3 7 ]
// and (with bla:="foo_perm") we print:
//  template <typename Type>
//  inline void foo_perm_8(Type *f)
//    { Type t=f[1];  f[1]=f[4];  f[4]=f[2];  f[2]=t; }
//    { Type t=f[3];  f[3]=f[5];  f[5]=f[6];  f[6]=t; }

// ========== HEADER FILE src/perm/radixpermute.h: ==========

void radix_permute(Type *f, ulong n, ulong r);
//
// swap elements with index pairs i, j where the
// radix-r representation of i and j are mutually
// digit-reversed (e.g. 436 <--> 634)
//
// This is a radix-r generalization of revbin_permute()
// revbin_permute(f, n)) =^= radix_permute(f, n, 2)
//
// must have:
//  n == p**x for some x>=1
//  r >= 2
//
// original by Andre Piotrowski
// this optimized version avoids the (n*log(n)) divisions
// by using two size-BITS_PER_LONG tables NT[], KT[]
//

// ========== HEADER FILE src/perm/revbinpermute.h: ==========

void revbin_permute(Type *f, ulong n);

// ========== HEADER FILE src/perm/revbinpermute0.h: ==========

void revbin_permute0(Type *f, ulong n);

// ========== HEADER FILE src/perm/reverse.h: ==========

inline void reverse(Type *f, ulong n);
// Reverse order of array f.

inline void reverse_0(Type *f, ulong n);
// Reverse array around index zero:

// ========== HEADER FILE src/perm/rotate.h: ==========

void rotate_left(Type *f, ulong n, ulong s);
// Rotate towards element #0
// Shift is taken modulo n

void rotate_right(Type *f, ulong n, ulong s);
// Rotate away from element #0
// Shift is taken modulo n

void rotate_left1(Type *f, ulong n);
// Rotate towards element #0, by one position.
// =^= rotate_left(f, n, 1);

void rotate_right1(Type *f, ulong n);
// Rotate away from element #0, by one position.
// =^= rotate_right(f, n, 1);

void rotate_sgn(Type *f, ulong n, long s);
// Positive s --> shift away from element zero

// ========== HEADER FILE src/perm/shortgraypermute.h: ==========

inline void gray_permute_2(Type */*f*/);
// unrolled version for length 2

inline void gray_permute_4(Type *f);
// unrolled version for length 4

inline void gray_permute_8(Type *f);
// unrolled version for length 8

inline void gray_permute_16(Type *f);
// unrolled version for length 16

inline void gray_permute_32(Type *f);
// unrolled version for length 32

inline void gray_permute_64(Type *f);
// unrolled version for length 64

inline void inverse_gray_permute_2(Type */*f*/);
// unrolled version for length 2

inline void inverse_gray_permute_4(Type *f);
// unrolled version for length 4

inline void inverse_gray_permute_8(Type *f);
// unrolled version for length 8

inline void inverse_gray_permute_16(Type *f);
// unrolled version for length 16

inline void inverse_gray_permute_32(Type *f);
// unrolled version for length 32

inline void inverse_gray_permute_64(Type *f);
// unrolled version for length 64

// ========== HEADER FILE src/perm/shortrevbinpermute.h: ==========

inline void revbin_permute_4(Type *f);
// unrolled version for length 4

inline void revbin_permute_8(Type *f);
// unrolled version for length 8

inline void revbin_permute_16(Type *f);
// unrolled version for length 16

inline void revbin_permute_32(Type *f);
// unrolled version for length 32

inline void revbin_permute_64(Type *f);
// unrolled version for length 64

inline void revbin_permute_leq_64(Type *f, ulong n);

// ========== HEADER FILE src/perm/shortrevbinpermute0.h: ==========

inline void revbin_permute0_4(Type *f);
// unrolled version for length 4

inline void revbin_permute0_8(Type *f);
// unrolled version for length 8

inline void revbin_permute0_16(Type *f);
// unrolled version for length 16

inline void revbin_permute0_32(Type *f);
// unrolled version for length 32

inline void revbin_permute0_64(Type *f);
// unrolled version for length 64

inline void revbin_permute0_leq_64(Type *f, ulong n);

// ========== HEADER FILE src/perm/swapblocks.h: ==========

void swap_blocks(Type *f, ulong x1, ulong n1, ulong x2, ulong n2);
// Swap the blocks starting at indices x1 and x2,
// n1 and n2 are the block lengths.

void inverse_swap_blocks(Type *f, ulong x1, ulong n1, ulong x2, ulong n2);
// Inverse of swap_blocks(f, x1, n1, x2, n2).
// Same effect as  swap_blocks(f, x1, n2, x2+n2-n1, n1).

// ========== HEADER FILE src/perm/xorpermute.h: ==========

inline void xor_permute(Type *f, ulong n, ulong x);
// Self-inverse.
// n must be divisible by the smallest power of 2
//   that is greater than x
// e.g. x=1  --> n must be even
// e.g. x=2,3  --> n must be divisible by four
// With n a power of 2 and x<n one is on the safe side

// ========== HEADER FILE src/perm/zip.h: ==========

// ----- SRCFILE=src/perm/zip.cc: -----
void zip(double *f, long n);
// lower half --> even indices
// upper half --> odd indices
// n must be a power of 2.
// same as transposing the array as 2 x n/2 - matrix
// useful to combine real/imag part into a Complex array
// called by real_imag_to_complex()

void unzip(double *f, long n);
// inverse of zip():
// put part of data with even indices
// sorted into the lower half,
// odd part into the upper half
// n must be a power of 2.
// same as transposing the array as n/2 x 2 - matrix
// useful to separate real/imag part from a Complex array
// called by complex_to_real_imag()

void zip(const Type * restrict f, Type * restrict g, ulong n);
// zip-permutation:
//   lower half --> even indices
//   upper half --> odd indices
// n must be even.
//.
// Same as transposing the array as 2 x n/2 - matrix.

void zip(Type *f, ulong n);
// zip-permutation, in-place version.
// n must be a power of 2.
//.
// Useful to combine real/imag part into a complex array.

void unzip(const Type * restrict f, Type * restrict g, ulong n);
// unzip-permutation:
//   even indices --> lower half
//    odd indices --> upper half
// n must be even.
// Inverse of zip().
//.
// Same as transposing the array as n/2 x 2 - matrix

void unzip(Type *f, ulong n);
// unzip-permutation, in-place version.
// n must be a power of 2
//.
// Useful to separate a complex array into real/imag part

// ========== HEADER FILE src/perm/ziprev.h: ==========

void zip_rev(const Type * restrict x, Type * restrict y, ulong n);
// reordering needed for fht based inverse dct
// n must be even

void zip_rev(Type *x, ulong n);
// in-place version
// n must be a power of 2

void unzip_rev(const Type * restrict x, Type * restrict y, ulong n);
// reordering needed for fht based dct
// n must be even

void unzip_rev(Type *x, ulong n);
// in-place version
// n must be a power of 2

