
// demo-is-self-contained

#include <cmath>

#include "fxttypes.h"

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

#include "fxtio.h"

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

//#define TIMING // uncomment to disable printing




ulong *a;
ulong ct = 0;

void visit(ulong off)
{
//    { // OEIS:
////        ulong d1=0;  // for A179254 and A179255
//        ulong d1=a[0];  // for A179269 and A007294
//        for (ulong k=1; k<off; ++k)
//        {
//            ulong d2 = a[k]-a[k-1];
////            if ( d2<=d1 ) return;  // A179254
////            if ( d2<d1 ) return;  // A179255
////            if ( d2<=d1 ) return;  // A179269
//            if ( d2<d1 ) return;  // A007294
//            d1=d2;
//        }
//    }
//    if ( (a[0]&1)==0 )  return;  // smallest part odd: A026832 (odd only if n is a square)

//        if ( a[0]!=1 ) return;  // least part == 1 A025147 (offset!)

//    for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[k-1])&1)!=1 )  return;  // A179080
//    if (a[0]&1)  return;  for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[k-1])&1)==1 )  return;  // A000009
//    if (0==(a[0]&1))  return;  for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[k-1])&1)==1 )  return;  // A000700
//    for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[k-1])&1)==1 )  return;  // A189357
//    for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[0])%2)!=0 )  return;  // A189357
//    for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[0])%2)==0 )  return;  // A000000

//    if ( (a[off-1] & 1)==0 )  return;  // A026837
//    if ( (a[off-1] & 1)!=0 )  return;  // A026838
//    if ( a[off-1]%3 !=0 )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( ((a[k]-a[k-1])%3)!=0 )  return;  // A000000

//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])<a[0] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])<=a[0] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])>a[0] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( a[k] < 2*a[k-1] )  return;  // A000929
//    for (ulong k=1; k<off; ++k)  if ( a[k] <= 2*a[k-1] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( a[k] >= 2*a[k-1] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( a[k] > 2*a[k-1] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])<=1 )  return;  // A003114
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])<=2 )  return;  // A025157

//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])<=a[k-1] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])<a[k-1] )  return;  // A000929
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])>a[k-1] )  return;  // A000000
//    for (ulong k=1; k<off; ++k)  if ( (a[k]-a[k-1])>=a[k-1] )  return;  // A000000

//    if ( off <= a[0] )  return;  // A000000
//    if ( off < a[0] )  return;  // A000000
//    if ( off > a[0] )  return;  // A025157
//    if ( off >= a[0] )  return;  // A000000

    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_dist_lex_rec(ulong n, ulong mp, ulong off=0)
{
    if ( n==0 )
    {
#ifndef TIMING
        visit(off);
#else
        ++ct;
#endif
        return;
    }

    const ulong d = 1;  // min distance between parts and minimal part
    // d==1:  A000009
    // d==2:  A003106
    // d==3:  A179046
    // d==4:  N/A
    for (ulong m=mp+d; m<=n; ++m)
    {
        a[off] = m;
        part_dist_lex_rec(n-m, m, off+1);
    }
}
// -------------------------

int
main(int argc, char **argv)
{
    ulong n = 9;
    NXARG(n, "Partitions of n");
    const ulong na = (ulong)floor( (sqrt(1+8*(double)n) - 1)/2 );  // max number of parts, see A003056
    a = new ulong[na];
//    cout << " na=" << na << endl;

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

    part_dist_lex_rec(n, mp);

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

    delete [] a;

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

/*
Timing:
% time ./bin 180
arg 1: 180 == n  [Partitions of n]  default=9
arg 2: 0 == mp  [Minimal part > mp,  0 <= mp < n]  default=0
 180:  ct=141231780

./bin 180  8.79s user 0.00s system 99% cpu 8.795 total
  ==> 141231780/8.79 == 16,067,324 per second
*/

/*
for OEIS:
echo $(for ((n=1; n<=20; ++n)); do ./bin $n 0 | g ct; done | sed 's/.*=//g;') | sed 's/ /,/g;'
echo $(for n in $(seq 1 60); do ./bin $n | g ct; done | cut -d= -f2) | sed 's/ /, /g'
*/

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