
// demo-is-self-contained

#include "demo/nextarg.h"
#include "fxttypes.h"  // ulong
#include "fxtiomanip.h"  // setprecision()
#include <cmath>  // sqrt(), fabs(), ...

//% TeX picture of dataflow for radix-2 fast transforms (butterfly diagram).

// define to use pict2e vectors:
#define USE_PICT2E  // default

inline void line(long x0, long y0, long x1, long y1)
// For \line(dx,dy){length} and \vector(dx,dy}{length}
// NOTE: The argument 'length' is the VERTICAL coordinate for
// vertical line segments, else the HORIZONTAL coordinate.
{
#ifdef USE_PICT2E

    double dx = x1 - x0;
    double dy = y1 - y0;

    // length:
    double len = sqrt( dx*dx + dy*dy );

    // slopes:
    long sx = (long)round( 999.0 * dx/len );
    long sy = (long)round( 999.0 * dy/len );
    // simplify for purely horiz/vert case:
    if ( sx==0 )  sy = 1;
    if ( sy==0 )  sx = 1;

    // "length" to be used with \vector:
    double vlen = fabs( dx );
    if ( fabs(vlen)<1e-4 )  vlen = 2;  // == abs( dy )

    cout << "\\put(" << x0 << "," << y0 << ")"
         << "{\\vector(" << sx <<","<< sy << ")"
         << "{" << setprecision(3) << vlen << "}}"
         << endl;

#else // USE_PICT2E

    cout << "\\curve("
         << x0 << "," << y0 << ", "
         << x1 <<","<< y1 << ")"
         << endl;

#endif // USE_PICT2E
}
// -------------------------


inline void line2(ulong t1, ulong t2, ulong ldm, bool pm)
{
    ulong y0 = 3*ldm;
    ulong y1 = y0+2;
    if ( pm )
    {
        line(t1, y0, t1, y1);
        line(t1, y0, t2, y1);
        line(t2, y0, t1, y1);

        double yt = (double)y0-0.5;
        cout << "\\put(" << (double)t1-0.2 << "," << yt << ")" << "{" << t1 << "}" << endl;
        cout << "\\put(" << (double)t2-0.2 << "," << yt << ")" << "{" << t2 << "}" << endl;
    }
    else
    {
        line(t2, y0, t2, y1);
    }
}
// -------------------------

void set_lt(bool pm)
{
    if ( pm )
    {
        cout << "%% additions:" << endl;
#ifdef USE_PICT2E
        cout << "\\linethickness{0.4mm}" << endl;
#else
        cout << "\\linethickness{0.3mm}" << endl;
#endif
    }
    else
    {
        cout << "%% subtractions:" << endl;
#ifdef USE_PICT2E
        cout << "\\linethickness{0.2mm}" << endl;
#else
        cout << "\\linethickness{0.1mm}" << endl;
#endif
    }
}
// -------------------------


void dit2_butterfly(ulong ldn, bool pm)
{
    ulong n = (1<<(ulong)ldn);
    for (ulong ldm=1; ldm<=ldn; ++ldm)
    {
        cout << "% ldm=" << ldm << endl;
        if ( pm )
        {
            cout << "\\put(" << n+2 << "," << 3*ldm+1 << "){ldm=" << ldm <<"}" << endl;
        }

        const ulong m = (1<<ldm);
        const ulong mh = (m>>1);
        for (ulong j=0; j<mh; ++j)
        {
            for (ulong r=0; r<n; r+=m)
            {
                const ulong t1 = r+j;
                const ulong t2 = t1+mh;

                line2(t1, t2, ldm, pm);

//                double u = f[t1];
//                double v = f[t2];
//                f[t1] = u + v;
//                f[t2] = u - v;
            }
        }
    }
}
// -------------------------



//template <typename Type>
void walsh_gray(ulong ldn, ulong pm)
{
    const ulong n = (1UL<<ldn);

    for (ulong ldm=ldn; ldm>0; --ldm) // dif
    {
        cout << "% ldm=" << ldm << endl;
        if ( pm )
        {
            cout << "\\put(" << n+2 << "," << 3*ldm+1 << "){ldm=" << ldm <<"}" << endl;
        }
        const ulong m = (1UL<<ldm);
        for (ulong r=0; r<n; r+=m)
        {
            ulong t1 = r;
            ulong t2 = r + m - 1;
            for (  ;  t1<t2;  ++t1,--t2)
            {
//                Type u = f[t1];
//                Type v = f[t2];
//                f[t1] = u + v;
//                f[t2] = u - v;
                line2(t1, t2, ldm, pm);
            }
        }
    }
}
// -------------------------


int
main(int argc, char **argv)
{
    ulong ldn = 4;
    NXARG(ldn,"length of tranform == 2**ldn");
    ulong wh = 1;
    NXARG(wh,"what to produce:"
          "  1==> Walsh radix-2 DIF (same as radix-2 DIF FFT)"
          "  2==> Walsh-gray"
          );

    switch ( wh )
    {
    case 1:
        set_lt(1); dit2_butterfly(ldn, 1);
        set_lt(0); dit2_butterfly(ldn, 0);
        break;
    case 2:
        set_lt(1); walsh_gray(ldn, 1);
        set_lt(0); walsh_gray(ldn, 0);
        break;
//    default:
//        set_lt(1); fht_dit2(ldn, 1);
//        set_lt(0); fht_dit2(ldn, 0);
//        break;
    }

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

/*
Embedding LaTeX code is:

\usepackage{curves}% <--=  before \begin{document}
%% or, when USE_PICT2E defined above
\usepackage{pict2e}% <--=  before \begin{document}

\begin{figure}%[hbt]
\begin{center}
\setlength{\unitlength}{7.0mm}
\begin{picture}(16.5,12.5)(+2.0,+2.3)
 [OUTPUT of the program HERE] <--= there!
\end{picture}
\end{center}
\caption{\jjlabel{fig:dit2butterfly}
Data flow for the length-16, radix-2, decimation in time (DIT) transform.}
\end{figure}

*/


/// Emacs:
/// Local Variables:
/// MyRelDir: "demo/fft"
/// makefile-dir: "../../"
/// make-target: "1demo DSRC=demo/fft/butterfly-texpic-demo.cc"
/// make-target2: "1demo DSRC=demo/fft/butterfly-texpic-demo.cc DEMOFLAGS=-DTIMING"
/// End:

