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

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

class cycles;
// compute and analyze cycles of a permutation

// ========== 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/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<=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);
// \forall i:  g[(i*r)%n] <- f[i]
// must have:  gcd(n,r)==1
//
// mrotate(f,n,1,g) =^= { copy(f,g,n); }
// mrotate(f,n,n-1,g) =^= { copy(f,g,n); reverse_0(g,n); }

void inverse_mrotate(const Type * restrict f, ulong n, ulong r, Type * restrict g);
// \forall 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[]:
// { copy(y, x, n); mrotate(x, n, r, y); copy(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:  \forall 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:  \forall i:  g[i] == f[(i*r)%n]
// Return zero if condition holds.

// ========== 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]  \forall 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]  \forall 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]]  \forall 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]]  \forall 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]  \forall k
// Must have:  0<=x(k)<n \forall 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]  \forall k
// Must have:  0<=x(k)<n \forall 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)]  \forall k
// Must have:  0<=x(k)<n \forall k, and x(i)!=x(j) \forall i!=j

void apply_inverse_permutation(ulong (*x)(ulong), Type *f, ulong n, bitarray *bp=0);
// Set f[k] <-- f[x(k)]  \forall k
// Must have:  0<=x(k)<n \forall k, and x(i)!=x(j) \forall 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[] is a derangement of the trivial permutation,
// i.e., 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[]

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_indecomposable(const ulong *f, ulong n);
// Return whether permutation is indecomposable,
// i.e. whether {f[0],f[1],...,f[k]} != {0,...,k} for all k<n-1

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_periods(const ulong *f, ulong n, ulong *p, bitarray *bp/*=0*/);
// Write to p[k] the period of element f[k]
// (period := length of cycle containing f[k])
// Return minimal number of transpositions required for the permutation.
// Example (n=11):
//   k:   f[k]  p[k]
//   0:    3     2
//   1:    7     3
//   2:    9     5
//   3:    0     2
//   4:    2     5
//   5:    1     3
//   6:   10     5
//   7:    5     3
//   8:    8     1
//   9:    6     5
//  10:    4     5
// return nt=7

// 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-cycle-type.h: ==========

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

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.

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

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

inline void next_num_derangements(double &dn0, double &dn1, double &n1);
// D(n) = (n-1) * ( D(n-1) + D(n-2) )

inline void init_derange_branch_ratios(double *b);
// Preccompute branching probabilities for random derangements.
// b[] == { 0, 1, 0.3333, 0.1818, 0.1698, 0.1423, 0.1250, ...}
// b[k] == (k-1) * D(k-2) / D(k)

inline double derange_branch_ratio(const double *b, ulong n);

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 permutation with no fixed points.
// 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-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).

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

void random_permute(Type *f, ulong n);
// Randomly permute the elements of f.
// Algorithm given by Helmut Herold, attributed to C.L.Robinson.

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

void random_permute_cyclic(Type *f, ulong n);
// Permute the elements of f by a random cyclic permutation.
// Algorithm by S.Sattolo:
//   swap last with rand(first, ..., last-1)
//   swap second last with rand(first, ..., second last -1)
//     ...
//   swap second with first

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

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

// ----- SRCFILE=src/perm/printcycles.cc: -----
ulong print_cycles(const ulong *f, ulong n, bitarray *bp/*=0*/);
// Print the cycles of the permutation.
// Return number of fixed points.

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

// ========== 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_le_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_le_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
// higher 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 higher 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
//   higher 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 --> higher 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

