
// demo-is-self-contained

#include "fxttypes.h"

#include "jjassert.h"
#include "nextarg.h"  // NXARG()

#include "fxtio.h"

//% Generate all integer partitions in lexicographic order, recursive algorithm.

//#define TIMING // uncomment to disable printing




ulong *a;
ulong ct = 0;

void visit(ulong off)
{
    // OEIS sequences:
//    { const ulong d=3; if ( a[0] < d )  return;  // A179046 (d==2 gives A003106)
//        for (ulong k=1; k<off; ++k)  if ( a[k]-a[k-1] < d )  return;
//    }

//    { const ulong d=3;  // A025157 (d==2 gives A003114)
//        for (ulong k=1; k<off; ++k)  if ( a[k]-a[k-1] < d )  return;
//    }

//    { if ( 0==(a[0] & 1) )  return;  // A179049, sum(n=0,N, x^(n*(n+1)/2)/prod(k=1,n,1-x^(2*k)))
//        for (ulong k=1; k<off; ++k)  if ( 0==((a[k]-a[k-1]) & 1) )  return;
//    }

//    {   // A179080, sum(n=0,N, x^(n*(n+1)/2)/prod(k=1,n+1,1-x^(2*k)))
//        for (ulong k=1; k<off; ++k)  if ( 0==((a[k]-a[k-1]) & 1) )  return;
//    }

//    {   //
////        const ulong lp = a[off-1]; // largest part k occurs at least k times: A003114
//        const ulong lp = a[0]; // least part k occurs at least k times: A188216
//        ulong lct = 0;
//        for (ulong k=0; k<off; ++k)  lct += (a[k]==lp);
//        if ( lct < lp )  return;
//    }

//    for (ulong k=off; (long)(k-1)>=0; k-=1)
//    {
//        if ( (a[k] % 2) && ( a[k] == a[k-1] ) )  return; // A006950 no odd part repeated
//        if ( !(a[k] % 2) && ( a[k] == a[k-1] ) )  return; // A001935 no even part repeated
//    }

//    if ( a[off-1] != off )  return;  // A047993 biggest part == number of parts


    cout << setw(4) << ++ct << ":  ";
    for (ulong k=0; k<off;  ++k)
    {
        cout << a[k];
        if ( k+1<off )  cout << "+";
    }
//    cout << "  [" << off << "]";  // number of parts
    cout << endl;
}
// -------------------------


void part_lex_rec(ulong n, ulong mp, ulong off=0)
// Partition n into parts m >= np.
{
    if ( n==0 )
    {
#ifndef TIMING
        visit(off);
#else
        ++ct;
#endif
        return;
    }
//    cout << ".";

    for (ulong m=mp; m<=n; ++m)
    {
        a[off] = m;
        part_lex_rec(n-m, m, off+1);
    }
}
// -------------------------

int
main(int argc, char **argv)
{
    ulong n = 9;
    NXARG(n, "Partitions of n");
    a = new ulong[n];

    ulong mp = 1;
    NXARG(mp, "Minimal part at least mp,  1 <= mp <= n");
    if ( mp<1 )  mp = 1;
    if ( mp>n )  mp = n;

    part_lex_rec(n, mp);

    cout << " " << n << ":  ct=" << ct << endl;
    cout << endl;

    delete [] a;

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

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

% time ./bin 100
arg 1: 100 == n  [Partitions of n]  default=6
arg 2: 1 == mp  [Minimal part at least mp,  1 <= mp <= n]  default=1
 100:  ct=190569292
./bin 100  7.10s user 0.00s system 99% cpu 7.135 total
  ==> 190569292/7.10 == 26,840,745 per second

*/


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