
#include "comb/mset-perm-lex.h"
#include "comb/mset-perm-2invtab.h"

#include "comb/comb-print.h"
#include "fxtiomanip.h"
//#include "jjassert.h"

#include <cstdlib>  // atol()
//#include "demo/nextarg.h"



//% All multiset permutations in lexicographic order, iterative generation.
//% Same as: all strings with fixed content.


//#define TIMING // uncomment to disable printing

int
main(int argc, char **argv)
{
    ulong k;   // number of sorts of elements
    ulong *r;  // element i is repeated r[i] times
    const bool dfz = true;  // whether to print dots for zeros

    cout << "args: multiplicities of elements" << endl;
    if ( argc<=1 )
    {
        ulong t[]={2, 2, 1, 0};  // proper multisets  ct=30
//        ulong t[]={1, 1, 1, 1, 0};  // permutations  ct = 24
//        ulong t[]={6, 2, 0};  // combinations  ct=28
        k=0;  while ( t[k] )  { ++k; }
        r = new ulong[k];
        for (ulong j=0; j<k; ++j)  r[j] = t[j];
    }
    else
    {
        k = argc - 1;
        r = new ulong[k];
        for (ulong j=0; j<k; ++j)
        {
            ulong t = atol(argv[j+1]);
            r[j] = t;
        }
    }

    mset_perm_lex P(r, k);

    cout << "multiplicities: ( ";
    for (ulong i=0; i<k; ++i)  cout << P.r_[i] << (i<k-1?", ":" ");
    cout << ")";
    cout << "  k=" << P.k_ << "  n=" << P.n_;
    cout << endl;

    const ulong n = P.n_;
    const ulong *x = P.data();
    // inversion table:
    ulong *it = new ulong[ n - 1 ];


    ulong ct = 0;
    do
    {
        ++ct;
#ifndef TIMING
        cout << setw(4) << ct << ":";
        print_perm("  ", x, n, dfz);

        msetperm2rinvtab(x, n, it);
        print_perm("    ", it, n-1, dfz);

        msetperm2linvtab(x, n, it);
        print_perm("    ", it, n-1, dfz);

        cout << endl;
#endif
    }
    while ( P.next() );


    cout << "ct=" << ct << endl;

    delete [] it;
    delete [] r;

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

/*
Timing:

% time ./bin 2 2 2 3 3 3
args: multiplicities of elements
multiplicities: ( 2, 2, 2, 3, 3, 3 )  k=6  n=15
ct=756756000
./bin 2 2 2 3 3 3  8.08s user 0.00s system 100% cpu 8.080 total
  ==> 756756000/8.08 == 93,657,920 per second

%  time ./bin 3 3 3 2 2 2 ## reordered
args: multiplicities of elements
multiplicities: ( 3, 3, 3, 2, 2, 2 )  k=6  n=15
ct=756756000
./bin 3 3 3 2 2 2  8.19s user 0.00s system 99% cpu 8.247 total
  ==> 756756000/8.19 == 92,400,000 per second

% time  ./bin 1 1 1 1 1 1 1 1 1 1 1 1  ## permutations of 12
args: multiplicities of elements
multiplicities: ( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )  k=12  n=12
ct=479001600
./bin 1 1 1 1 1 1 1 1 1 1 1 1  3.77s user 0.00s system 99% cpu 3.779 total
  ==> 479001600/3.77 == 127,056,127 per second

% time  ./bin 15 15  ## combination (30 choose 15)
args: multiplicities of elements
multiplicities: ( 15, 15 )  k=2  n=30
ct=155117520
./bin 15 15  2.61s user 0.00s system 99% cpu 2.608 total
  ==> 155117520/2.61 == 59,432,000 per second


BENCHARGS= 2 2 2 3 3 3
BENCHARGS= 3 3 3 2 2 2 ## reordered
BENCHARGS= 1 1 1 1 1 1 1 1 1 1 1 1  ## permutations of 12
BENCHARGS= 15 15  ## combinations (30 choose 15)
*/


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