
#include "perm/perm-genus.h"  // perm_genus()
#include "comb/perm-lex-inv.h"

#include "ds/bitarray.h"

//#include "comb/perm-trotter.h"
//#include "comb/perm-gray-rfact.h"

#include "perm/printcycles.h"


#include "fxttypes.h"
#include "fxtio.h"
#include "nextarg.h"

#include "jjassert.h"


//% Genus of all permutations of n elements.
//% Print parenthesis strings for permutations of genus zero.

// See sequence A177267 of the OEIS.


//#define TIMING // uncomment to disable printing

// Whether to draw parenthesis strings for permutations of genus zero:
#define DRAW_ZG_PARENS


int
main(int argc, char **argv)
{
    ulong n = 4;
    NXARG(n, "Permutations of n elements.");

    bool dfz = true;  // whether to print dots for zeros
    ulong gct[32];  // genus histogram
    for (ulong j=0; j<n; ++j)  gct[j] = 0;
    ulong cpi[32];  // for rotated inverse permutation
    bitarray B(n);  // aux for computation of genus

    perm_lex_inv P(n);  // used because inverse permutations are available
//    perm_trotter P(n);
//    perm_gray_rfact P(n);

    const ulong *p = P.data(), *pi = P.invdata();

#ifdef DRAW_ZG_PARENS
    bitarray C(2*n);  // binary paren strings
#endif

//    ulong zct = 0; // count permutations that have same genus as their inverses
    ulong ct = 0;
    do
    {
#ifndef TIMING
        cout << setw(4) << ct << ":";
#endif
        ++ct;

        const ulong gen = perm_genus(p, n, pi, cpi, &B);
        gct[gen] += 1;

#ifndef TIMING
        print_vec("    ", p, n, dfz);
        cout << "  " << gen;
//        P.print_inv("    ", dfz);
        cout << "   ";  print_cycles(p, n, &B);
        cout << "   ";  print_cycles(cpi, n, &B);

#ifdef DRAW_ZG_PARENS
        if ( gen == 0 )
        {
            genus0_perm_to_paren(p, n, C);
            C.dump_bits();
            cout << "   ";
            for (ulong j=0; j<2*n; ++j)
                cout << ( C.test(j) ? '(' : ')' );
        }
#endif

        cout << endl;

//        jjassert( gen == perm_genus(pi, n, p, cpi, &B) );  // not true
//        zct += ( gen == perm_genus(pi, n, p, cpi, &B) );

#endif
    }
    while ( P.next() );
    cout << "  ct=" << ct << endl;
//    cout << "  zct=" << zct << endl;   // 1, 2, 4, 14, 68, 390, 2588 A000000

    for (ulong j=0; j<(n+1)/2; ++j)  { cout << gct[j] << ", "; ct-=gct[j]; }
    cout << endl;
    jjassert( ct==0 );

    return 0;
}
// -------------------------

/*

1,
2,
5, 1,
14, 10,
42, 70, 8,
132, 420, 168,
429, 2310, 2121, 180,
1430, 12012, 20790, 6088,
4862, 60060, 174174, 115720, 8064,
16796, 291720, 1309308, 1624480, 386496,
58786, 1385670, 9087078, 18748730, 10031736, 604800,
208012, 6466460, 59306676, 188208020, 186698512, 38113920,
742900, 29745716, 368588220, 1700309468, 2788065280, 1271140416, 68428800,

Columns are
A000108 (2n)!/(n!(n+1)!
A002802 (2*n+3)!/(6*n!*(n+1)!)

*/


/*
Timing: (AMD Phenom II X4 945 3000MHz)

% time ./bin 11
./bin 11  7.49s user 0.00s system 99% cpu 7.491 total
  ==> 11!/7.49 == 5,329,345 per second

% time ./bin 12
./bin 12  95.58s user 0.00s system 99% cpu 1:35.60 total
  ==> 12!/95.58 == 5,011,525 per second

% time ./bin 13
./bin 13  1312.64s user 0.00s system 99% cpu 21:52.85 total
  ==> 13!/1312.64 == 4,743,890 per second

*/

/// Emacs:
/// Local Variables:
/// MyRelDir: "demo/comb"
/// makefile-dir: "../../"
/// make-target: "1demo DSRC=demo/comb/perm-genus-demo.cc"
/// make-target2: "1demo DSRC=demo/comb/perm-genus-demo.cc DEMOFLAGS=-DTIMING"
/// End:

