
// demo-is-self-contained

#include "fxttypes.h"
#include "fxtiomanip.h"
#include "jjassert.h"
#include "demo/nextarg.h"


//% Run length limited (RLL) Words (at most 2 identical consecutive bits),
//% recursive CAT algorithm.

//#define TIMING  // define to disable printing


ulong n;    // number of bits in words
ulong *rv;  // bits of the word

ulong ct;   // count objects
ulong rct;  // count recursions (==work)

void visit()
{
#ifndef TIMING
    cout << setw(4) << ct << ":";
    cout << "   ";
    cout << " .";  // assume highest bit in RLL word is zero
    for (ulong j=0; j<n; ++j)  cout << " " << (rv[j] ? '1' : '.');

    cout << "   ";
    cout << " " << (!rv[0] ? '1' : '.');  // assume highest bit in RLL word is zero
    for (ulong j=1; j<n; ++j)  cout << " " << (rv[j]==rv[j-1] ? '1' : '.');

    cout << endl;
#endif
}
// -------------------------


void rll_rec(ulong d, bool z)
{
    if ( d>=n )
    {
        ++ct;  // count objects
        visit();
    }
    else
    {
        ++rct;  // measure computational work
        if ( z==0 )
        {
            rv[d]=0;  rv[d+1]=1;  rll_rec(d+2, 1);
            rv[d]=1;  rll_rec(d+1, 1);
        }
        else  // z==1
        {
            rv[d]=0;  rll_rec(d+1, 0);
            rv[d]=1;  rv[d+1]=0;  rll_rec(d+2, 0);
        }
    }
}
// -------------------------


void rll_rec2(ulong d, bool z)
{
    if ( d>=n )
    {
        ++ct;  // count objects
        visit();
    }
    else
    {
        ++rct;  // measure computational work
        if ( z==0 )
        {
            rv[d]=0;  rv[d+1]=1;  rll_rec2(d+2, 1);
            rv[d]=1;  rll_rec2(d+1, 1);
        }
        else  // z==1
        {
            rv[d]=1;  rv[d+1]=0;  rll_rec2(d+2, 0);
            rv[d]=0;  rll_rec2(d+1, 0);
        }
    }
}
// -------------------------


int
main(int argc, char **argv)
{
    n = 7;
    NXARG(n, "Length of RLL words == n+1");
    rv = new ulong[n+1];  // incl. sentinel rv[n]

    ct = 0;
    rct = 0;

    rll_rec(0, 0);

    cout << "ct=" << ct << endl;
    cout << "rct=" << rct << endl;  // rct == ct-1
    cout << "work/object=" << (double)rct/(double)ct << endl;  // ratio <= 1

    delete [] rv;

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

/*
Timing:

% time ./bin 41
arg 1: 41 == n  [Length of RLL words == n+1]  default=7
ct=433494437
rct=433494436
work/object=1
./bin 41  4.38s user 0.00s system 100% cpu 4.380 total
 ==> 433494437/4.38 == 98,971,332 per second

*/

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

