/**CFile****************************************************************

  FileName    [extraBddKmap.c]

  PackageName [extra]

  Synopsis    [Visualizing the K-map.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 2.0. Started - September 1, 2003.]

  Revision    [$Id: extraBddKmap.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $]

***********************************************************************/

///      K-map visualization using pseudo graphics      ///
///       Version 1.0. Started - August 20, 2000        ///
///     Version 2.0. Added to EXTRA - July 17, 2001     ///

#include "extraBdd.h"

#ifdef WIN32
#include <windows.h>
#endif

ABC_NAMESPACE_IMPL_START


/*---------------------------------------------------------------------------*/
/* Constant declarations                                                     */
/*---------------------------------------------------------------------------*/

// the maximum number of variables in the Karnaugh Map
#define MAXVARS 20

/*
// single line
#define SINGLE_VERTICAL     (char)179
#define SINGLE_HORIZONTAL   (char)196
#define SINGLE_TOP_LEFT     (char)218
#define SINGLE_TOP_RIGHT    (char)191
#define SINGLE_BOT_LEFT     (char)192
#define SINGLE_BOT_RIGHT    (char)217

// double line
#define DOUBLE_VERTICAL     (char)186
#define DOUBLE_HORIZONTAL   (char)205
#define DOUBLE_TOP_LEFT     (char)201
#define DOUBLE_TOP_RIGHT    (char)187
#define DOUBLE_BOT_LEFT     (char)200
#define DOUBLE_BOT_RIGHT    (char)188

// line intersections
#define SINGLES_CROSS       (char)197
#define DOUBLES_CROSS       (char)206
#define S_HOR_CROSS_D_VER   (char)215
#define S_VER_CROSS_D_HOR   (char)216

// single line joining
#define S_JOINS_S_VER_LEFT  (char)180
#define S_JOINS_S_VER_RIGHT (char)195
#define S_JOINS_S_HOR_TOP   (char)193
#define S_JOINS_S_HOR_BOT   (char)194

// double line joining
#define D_JOINS_D_VER_LEFT  (char)185
#define D_JOINS_D_VER_RIGHT (char)204
#define D_JOINS_D_HOR_TOP   (char)202
#define D_JOINS_D_HOR_BOT   (char)203

// single line joining double line
#define S_JOINS_D_VER_LEFT  (char)182
#define S_JOINS_D_VER_RIGHT (char)199
#define S_JOINS_D_HOR_TOP   (char)207
#define S_JOINS_D_HOR_BOT   (char)209
*/

// single line
#define SINGLE_VERTICAL     (char)'|'
#define SINGLE_HORIZONTAL   (char)'-'
#define SINGLE_TOP_LEFT     (char)'+'
#define SINGLE_TOP_RIGHT    (char)'+'
#define SINGLE_BOT_LEFT     (char)'+'
#define SINGLE_BOT_RIGHT    (char)'+'

// double line
#define DOUBLE_VERTICAL     (char)'|'
#define DOUBLE_HORIZONTAL   (char)'-'
#define DOUBLE_TOP_LEFT     (char)'+'
#define DOUBLE_TOP_RIGHT    (char)'+'
#define DOUBLE_BOT_LEFT     (char)'+'
#define DOUBLE_BOT_RIGHT    (char)'+'

// line intersections
#define SINGLES_CROSS       (char)'+'
#define DOUBLES_CROSS       (char)'+'
#define S_HOR_CROSS_D_VER   (char)'+'
#define S_VER_CROSS_D_HOR   (char)'+'

// single line joining
#define S_JOINS_S_VER_LEFT  (char)'+'
#define S_JOINS_S_VER_RIGHT (char)'+'
#define S_JOINS_S_HOR_TOP   (char)'+'
#define S_JOINS_S_HOR_BOT   (char)'+'

// double line joining
#define D_JOINS_D_VER_LEFT  (char)'+'
#define D_JOINS_D_VER_RIGHT (char)'+'
#define D_JOINS_D_HOR_TOP   (char)'+'
#define D_JOINS_D_HOR_BOT   (char)'+'

// single line joining double line
#define S_JOINS_D_VER_LEFT  (char)'+'
#define S_JOINS_D_VER_RIGHT (char)'+'
#define S_JOINS_D_HOR_TOP   (char)'+'
#define S_JOINS_D_HOR_BOT   (char)'+'


// other symbols
#define UNDERSCORE          (char)95
//#define SYMBOL_ZERO       (char)248   // degree sign
//#define SYMBOL_ZERO         (char)'o'
#ifdef WIN32
#define SYMBOL_ZERO         (char)'0'
#else
#define SYMBOL_ZERO         (char)' '
#endif
#define SYMBOL_ONE          (char)'1'
#define SYMBOL_DC           (char)'-'
#define SYMBOL_OVERLAP      (char)'?'

// full cells and half cells
#define CELL_FREE           (char)32
#define CELL_FULL           (char)219
#define HALF_UPPER          (char)223
#define HALF_LOWER          (char)220
#define HALF_LEFT           (char)221
#define HALF_RIGHT          (char)222


/*---------------------------------------------------------------------------*/
/* Structure declarations                                                    */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Type declarations                                                         */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Variable declarations                                                     */
/*---------------------------------------------------------------------------*/

// the array of BDD variables used internally
static DdNode * s_XVars[MAXVARS];

// flag which determines where the horizontal variable names are printed
static int fHorizontalVarNamesPrintedAbove = 1;

/*---------------------------------------------------------------------------*/
/* Macro declarations                                                        */
/*---------------------------------------------------------------------------*/


/**AutomaticStart*************************************************************/

/*---------------------------------------------------------------------------*/
/* Static function prototypes                                                */
/*---------------------------------------------------------------------------*/

// Oleg's way of generating the gray code
static int GrayCode( int BinCode );
static int BinCode ( int GrayCode );

/**AutomaticEnd***************************************************************/


/*---------------------------------------------------------------------------*/
/* Definition of exported functions                                          */
/*---------------------------------------------------------------------------*/


/**Function********************************************************************

  Synopsis    [Prints the K-map of the function.]

  Description [If the pointer to the array of variables XVars is NULL,
               fSuppType determines how the support will be determined.
               fSuppType == 0 -- takes the first nVars of the manager
               fSuppType == 1 -- takes the topmost nVars of the manager
               fSuppType == 2 -- determines support from the on-set and the offset
               ]

  SideEffects []

  SeeAlso     []

******************************************************************************/
void Extra_PrintKMap( 
  FILE * Output,  /* the output stream */
  DdManager * dd, 
  DdNode * OnSet, 
  DdNode * OffSet, 
  int nVars, 
  DdNode ** XVars, 
  int fSuppType, /* the flag which determines how support is computed */
  char ** pVarNames )
{
    int fPrintTruth = 1;
    int d, p, n, s, v, h, w;
    int nVarsVer;
    int nVarsHor;
    int nCellsVer;
    int nCellsHor;
    int nSkipSpaces;

    // make sure that on-set and off-set do not overlap
    if ( !Cudd_bddLeq( dd, OnSet, Cudd_Not(OffSet) ) )
    {
        fprintf( Output, "PrintKMap(): The on-set and the off-set overlap\n" );
        return;
    }

    // print truth table for debugging
    if ( fPrintTruth )
    {
        DdNode * bCube, * bPart;
        printf( "Truth table: " );
        if ( nVars == 0 )
            printf( "Constant" );
        else if ( nVars == 1 )
            printf( "1-var function" );
        else
        {
//            printf( "0x" );
            for ( d = (1<<(nVars-2)) - 1; d >= 0; d-- )
            {
                int Value = 0;
                for ( s = 0; s < 4; s++ )
                {
                    bCube = Extra_bddBitsToCube( dd, 4*d+s, nVars, dd->vars, 0 );   Cudd_Ref( bCube );
                    bPart = Cudd_Cofactor( dd, OnSet, bCube );                      Cudd_Ref( bPart );
                    Value |= ((int)(bPart == b1) << s);
                    Cudd_RecursiveDeref( dd, bPart );
                    Cudd_RecursiveDeref( dd, bCube );
                }
                if ( Value < 10 )
                    fprintf( stdout, "%d", Value );
                else
                    fprintf( stdout, "%c", 'a' + Value-10 );
            }
        }
        printf( "\n" );
    }


/*
    if ( OnSet == b1 )
    {
        fprintf( Output, "PrintKMap(): Constant 1\n" );
        return;
    }
    if ( OffSet == b1 )
    {
        fprintf( Output, "PrintKMap(): Constant 0\n" );
        return;
    }
*/
    if ( nVars < 0 || nVars > MAXVARS )
    {
        fprintf( Output, "PrintKMap(): The number of variables is less than zero or more than %d\n", MAXVARS );
        return;
    }

    // determine the support if it is not given
    if ( XVars == NULL )
    {
        if ( fSuppType == 0 )
        {   // assume that the support includes the first nVars of the manager
            assert( nVars );
            for ( v = 0; v < nVars; v++ )
                s_XVars[v] = Cudd_bddIthVar( dd, v );
        }
        else if ( fSuppType == 1 )
        {   // assume that the support includes the topmost nVars of the manager
            assert( nVars );
            for ( v = 0; v < nVars; v++ )
                s_XVars[v] = Cudd_bddIthVar( dd, dd->invperm[v] );
        }
        else // determine the support
        {
            DdNode * SuppOn, * SuppOff, * Supp;
            int cVars = 0;
            DdNode * TempSupp;

            // determine support
            SuppOn = Cudd_Support( dd, OnSet );         Cudd_Ref( SuppOn );
            SuppOff = Cudd_Support( dd, OffSet );       Cudd_Ref( SuppOff );
            Supp = Cudd_bddAnd( dd, SuppOn, SuppOff );  Cudd_Ref( Supp );
            Cudd_RecursiveDeref( dd, SuppOn );
            Cudd_RecursiveDeref( dd, SuppOff );

            nVars = Cudd_SupportSize( dd, Supp );
            if ( nVars > MAXVARS )
            {
                fprintf( Output, "PrintKMap(): The number of variables is more than %d\n", MAXVARS );
                Cudd_RecursiveDeref( dd, Supp );
                return;
            }

            // assign variables
            for ( TempSupp = Supp; TempSupp != dd->one; TempSupp = Cudd_T(TempSupp), cVars++ )
                s_XVars[cVars] = Cudd_bddIthVar( dd, TempSupp->index );

            Cudd_RecursiveDeref( dd, TempSupp );
        }
    }
    else
    {
        // copy variables
        assert( XVars );
        for ( v = 0; v < nVars; v++ )
            s_XVars[v] = XVars[v];
    }

    ////////////////////////////////////////////////////////////////////
    // determine the Karnaugh map parameters
    nVarsVer = nVars/2;
    nVarsHor = nVars - nVarsVer;

    nCellsVer = (1<<nVarsVer);
    nCellsHor = (1<<nVarsHor);
    nSkipSpaces = nVarsVer + 1;

    ////////////////////////////////////////////////////////////////////
    // print variable names
    fprintf( Output, "\n" );
    for ( w = 0; w < nVarsVer; w++ )
        if ( pVarNames == NULL )
            fprintf( Output, "%c", 'a'+nVarsHor+w );
        else
            fprintf( Output, " %s", pVarNames[nVarsHor+w] );

    if ( fHorizontalVarNamesPrintedAbove )
    {
        fprintf( Output, " \\ " );
        for ( w = 0; w < nVarsHor; w++ )
            if ( pVarNames == NULL )
                fprintf( Output, "%c", 'a'+w );
            else
                fprintf( Output, "%s ", pVarNames[w] );
    }
    fprintf( Output, "\n" );

    if ( fHorizontalVarNamesPrintedAbove )
    {
        ////////////////////////////////////////////////////////////////////
        // print horizontal digits
        for ( d = 0; d < nVarsHor; d++ )
        {
            for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
            for ( n = 0; n < nCellsHor; n++ )
                if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
                    fprintf( Output, "1   " );
                else
                    fprintf( Output, "0   " );
            fprintf( Output, "\n" );
        }
    }

    ////////////////////////////////////////////////////////////////////
    // print the upper line
    for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
    fprintf( Output, "%c", DOUBLE_TOP_LEFT );
    for ( s = 0; s < nCellsHor; s++ )
    {
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        if ( s != nCellsHor-1 )
        {
            if ( s&1 )
                fprintf( Output, "%c", D_JOINS_D_HOR_BOT );
            else
                fprintf( Output, "%c", S_JOINS_D_HOR_BOT );
        }
    }
    fprintf( Output, "%c", DOUBLE_TOP_RIGHT );
    fprintf( Output, "\n" );

    ////////////////////////////////////////////////////////////////////
    // print the map
    for ( v = 0; v < nCellsVer; v++ )
    {
        DdNode * CubeVerBDD;

        // print horizontal digits
//      for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
        for ( n = 0; n < nVarsVer; n++ )
            if ( GrayCode(v) & (1<<(nVarsVer-1-n)) )
                fprintf( Output, "1" );
            else
                fprintf( Output, "0" );
        fprintf( Output, " " );

        // find vertical cube
        CubeVerBDD = Extra_bddBitsToCube( dd, GrayCode(v), nVarsVer, s_XVars+nVarsHor, 1 );    Cudd_Ref( CubeVerBDD );

        // print text line
        fprintf( Output, "%c", DOUBLE_VERTICAL );
        for ( h = 0; h < nCellsHor; h++ )
        {
            DdNode * CubeHorBDD, * Prod, * ValueOnSet, * ValueOffSet;

            fprintf( Output, " " );
//          fprintf( Output, "x" );
            ///////////////////////////////////////////////////////////////
            // determine what should be printed
            CubeHorBDD  = Extra_bddBitsToCube( dd, GrayCode(h), nVarsHor, s_XVars, 1 );    Cudd_Ref( CubeHorBDD );
            Prod = Cudd_bddAnd( dd, CubeHorBDD, CubeVerBDD );                   Cudd_Ref( Prod );
            Cudd_RecursiveDeref( dd, CubeHorBDD );

            ValueOnSet  = Cudd_Cofactor( dd, OnSet, Prod );                     Cudd_Ref( ValueOnSet );
            ValueOffSet = Cudd_Cofactor( dd, OffSet, Prod );                    Cudd_Ref( ValueOffSet );
            Cudd_RecursiveDeref( dd, Prod );

#ifdef WIN32
            {
            HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
            char Symb = 0, Color = 0;
            if ( ValueOnSet == b1 && ValueOffSet == b0 )
                Symb = SYMBOL_ONE,     Color = 14;  // yellow
            else if ( ValueOnSet == b0 && ValueOffSet == b1 )
                Symb = SYMBOL_ZERO,    Color = 11;  // blue
            else if ( ValueOnSet == b0 && ValueOffSet == b0 ) 
                Symb = SYMBOL_DC,      Color = 10;  // green
            else if ( ValueOnSet == b1 && ValueOffSet == b1 ) 
                Symb = SYMBOL_OVERLAP, Color = 12;  // red
            else
                assert(0);
            SetConsoleTextAttribute( hConsole, Color );
            fprintf( Output, "%c", Symb );
            SetConsoleTextAttribute( hConsole, 7 );
            }
#else
            {
            if ( ValueOnSet == b1 && ValueOffSet == b0 )
                fprintf( Output, "%c", SYMBOL_ONE );
            else if ( ValueOnSet == b0 && ValueOffSet == b1 )
                fprintf( Output, "%c", SYMBOL_ZERO );
            else if ( ValueOnSet == b0 && ValueOffSet == b0 ) 
                fprintf( Output, "%c", SYMBOL_DC );
            else if ( ValueOnSet == b1 && ValueOffSet == b1 ) 
                fprintf( Output, "%c", SYMBOL_OVERLAP );
            else
                assert(0);
            }
#endif

            Cudd_RecursiveDeref( dd, ValueOnSet );
            Cudd_RecursiveDeref( dd, ValueOffSet );
            ///////////////////////////////////////////////////////////////
            fprintf( Output, " " );

            if ( h != nCellsHor-1 )
            {
                if ( h&1 )
                    fprintf( Output, "%c", DOUBLE_VERTICAL );
                else
                    fprintf( Output, "%c", SINGLE_VERTICAL );
            }
        }
        fprintf( Output, "%c", DOUBLE_VERTICAL );
        fprintf( Output, "\n" );

        Cudd_RecursiveDeref( dd, CubeVerBDD );

        if ( v != nCellsVer-1 )
        // print separator line
        {
            for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
            if ( v&1 )
            {
                fprintf( Output, "%c", D_JOINS_D_VER_RIGHT );
                for ( s = 0; s < nCellsHor; s++ )
                {
                    fprintf( Output, "%c", DOUBLE_HORIZONTAL );
                    fprintf( Output, "%c", DOUBLE_HORIZONTAL );
                    fprintf( Output, "%c", DOUBLE_HORIZONTAL );
                    if ( s != nCellsHor-1 )
                    {
                        if ( s&1 )
                            fprintf( Output, "%c", DOUBLES_CROSS );
                        else
                            fprintf( Output, "%c", S_VER_CROSS_D_HOR );
                    }
                }
                fprintf( Output, "%c", D_JOINS_D_VER_LEFT );
            }
            else
            {
                fprintf( Output, "%c", S_JOINS_D_VER_RIGHT );
                for ( s = 0; s < nCellsHor; s++ )
                {
                    fprintf( Output, "%c", SINGLE_HORIZONTAL );
                    fprintf( Output, "%c", SINGLE_HORIZONTAL );
                    fprintf( Output, "%c", SINGLE_HORIZONTAL );
                    if ( s != nCellsHor-1 )
                    {
                        if ( s&1 )
                            fprintf( Output, "%c", S_HOR_CROSS_D_VER );
                        else
                            fprintf( Output, "%c", SINGLES_CROSS );
                    }
                }
                fprintf( Output, "%c", S_JOINS_D_VER_LEFT );
            }
            fprintf( Output, "\n" );
        }
    }
    
    ////////////////////////////////////////////////////////////////////
    // print the lower line
    for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
    fprintf( Output, "%c", DOUBLE_BOT_LEFT );
    for ( s = 0; s < nCellsHor; s++ )
    {
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        if ( s != nCellsHor-1 )
        {
            if ( s&1 )
                fprintf( Output, "%c", D_JOINS_D_HOR_TOP );
            else
                fprintf( Output, "%c", S_JOINS_D_HOR_TOP );
        }
    }
    fprintf( Output, "%c", DOUBLE_BOT_RIGHT );
    fprintf( Output, "\n" );

    if ( !fHorizontalVarNamesPrintedAbove )
    {
        ////////////////////////////////////////////////////////////////////
        // print horizontal digits
        for ( d = 0; d < nVarsHor; d++ )
        {
            for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
            for ( n = 0; n < nCellsHor; n++ )
                if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
                    fprintf( Output, "1   " );
                else
                    fprintf( Output, "0   " );

            /////////////////////////////////
            fprintf( Output, "%c", (char)('a'+d) );
            /////////////////////////////////
            fprintf( Output, "\n" );
        }
    }
}



/**Function********************************************************************

  Synopsis    [Prints the K-map of the relation.]

  Description [Assumes that the relation depends the first nXVars of XVars and 
  the first nYVars of YVars. Draws X and Y vars and vertical and horizontal vars.]

  SideEffects []

  SeeAlso     []

******************************************************************************/
void Extra_PrintKMapRelation( 
  FILE * Output,  /* the output stream */
  DdManager * dd, 
  DdNode * OnSet, 
  DdNode * OffSet, 
  int nXVars, 
  int nYVars, 
  DdNode ** XVars, 
  DdNode ** YVars ) /* the flag which determines how support is computed */
{
    int d, p, n, s, v, h, w;
    int nVars;
    int nVarsVer;
    int nVarsHor;
    int nCellsVer;
    int nCellsHor;
    int nSkipSpaces;

    // make sure that on-set and off-set do not overlap
    if ( !Cudd_bddLeq( dd, OnSet, Cudd_Not(OffSet) ) )
    {
        fprintf( Output, "PrintKMap(): The on-set and the off-set overlap\n" );
        return;
    }

    if ( OnSet == b1 )
    {
        fprintf( Output, "PrintKMap(): Constant 1\n" );
        return;
    }
    if ( OffSet == b1 )
    {
        fprintf( Output, "PrintKMap(): Constant 0\n" );
        return;
    }

    nVars = nXVars + nYVars;
    if ( nVars < 0 || nVars > MAXVARS )
    {
        fprintf( Output, "PrintKMap(): The number of variables is less than zero or more than %d\n", MAXVARS );
        return;
    }


    ////////////////////////////////////////////////////////////////////
    // determine the Karnaugh map parameters
    nVarsVer = nXVars;
    nVarsHor = nYVars;
    nCellsVer = (1<<nVarsVer);
    nCellsHor = (1<<nVarsHor);
    nSkipSpaces = nVarsVer + 1;

    ////////////////////////////////////////////////////////////////////
    // print variable names
    fprintf( Output, "\n" );
    for ( w = 0; w < nVarsVer; w++ )
        fprintf( Output, "%c", 'a'+nVarsHor+w );
    if ( fHorizontalVarNamesPrintedAbove )
    {
        fprintf( Output, " \\ " );
        for ( w = 0; w < nVarsHor; w++ )
            fprintf( Output, "%c", 'a'+w );
    }
    fprintf( Output, "\n" );

    if ( fHorizontalVarNamesPrintedAbove )
    {
        ////////////////////////////////////////////////////////////////////
        // print horizontal digits
        for ( d = 0; d < nVarsHor; d++ )
        {
            for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
            for ( n = 0; n < nCellsHor; n++ )
                if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
                    fprintf( Output, "1   " );
                else
                    fprintf( Output, "0   " );
            fprintf( Output, "\n" );
        }
    }

    ////////////////////////////////////////////////////////////////////
    // print the upper line
    for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
    fprintf( Output, "%c", DOUBLE_TOP_LEFT );
    for ( s = 0; s < nCellsHor; s++ )
    {
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        if ( s != nCellsHor-1 )
        {
            if ( s&1 )
                fprintf( Output, "%c", D_JOINS_D_HOR_BOT );
            else
                fprintf( Output, "%c", S_JOINS_D_HOR_BOT );
        }
    }
    fprintf( Output, "%c", DOUBLE_TOP_RIGHT );
    fprintf( Output, "\n" );

    ////////////////////////////////////////////////////////////////////
    // print the map
    for ( v = 0; v < nCellsVer; v++ )
    {
        DdNode * CubeVerBDD;

        // print horizontal digits
//      for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
        for ( n = 0; n < nVarsVer; n++ )
            if ( GrayCode(v) & (1<<(nVarsVer-1-n)) )
                fprintf( Output, "1" );
            else
                fprintf( Output, "0" );
        fprintf( Output, " " );

        // find vertical cube
//      CubeVerBDD = Extra_bddBitsToCube( dd, GrayCode(v), nVarsVer, s_XVars+nVarsHor );    Cudd_Ref( CubeVerBDD );
        CubeVerBDD = Extra_bddBitsToCube( dd, GrayCode(v), nXVars, XVars, 1 );                 Cudd_Ref( CubeVerBDD );

        // print text line
        fprintf( Output, "%c", DOUBLE_VERTICAL );
        for ( h = 0; h < nCellsHor; h++ )
        {
            DdNode * CubeHorBDD, * Prod, * ValueOnSet, * ValueOffSet;

            fprintf( Output, " " );
//          fprintf( Output, "x" );
            ///////////////////////////////////////////////////////////////
            // determine what should be printed
//          CubeHorBDD  = Extra_bddBitsToCube( dd, GrayCode(h), nVarsHor, s_XVars );    Cudd_Ref( CubeHorBDD );
            CubeHorBDD  = Extra_bddBitsToCube( dd, GrayCode(h), nYVars, YVars, 1 );        Cudd_Ref( CubeHorBDD );
            Prod = Cudd_bddAnd( dd, CubeHorBDD, CubeVerBDD );                           Cudd_Ref( Prod );
            Cudd_RecursiveDeref( dd, CubeHorBDD );

            ValueOnSet  = Cudd_Cofactor( dd, OnSet, Prod );                     Cudd_Ref( ValueOnSet );
            ValueOffSet = Cudd_Cofactor( dd, OffSet, Prod );                    Cudd_Ref( ValueOffSet );
            Cudd_RecursiveDeref( dd, Prod );

            if ( ValueOnSet == b1 && ValueOffSet == b0 )
                fprintf( Output, "%c", SYMBOL_ONE );
            else if ( ValueOnSet == b0 && ValueOffSet == b1 )
                fprintf( Output, "%c", SYMBOL_ZERO );
            else if ( ValueOnSet == b0 && ValueOffSet == b0 ) 
                fprintf( Output, "%c", SYMBOL_DC );
            else if ( ValueOnSet == b1 && ValueOffSet == b1 ) 
                fprintf( Output, "%c", SYMBOL_OVERLAP );
            else
                assert(0);

            Cudd_RecursiveDeref( dd, ValueOnSet );
            Cudd_RecursiveDeref( dd, ValueOffSet );
            ///////////////////////////////////////////////////////////////
            fprintf( Output, " " );

            if ( h != nCellsHor-1 )
            {
                if ( h&1 )
                    fprintf( Output, "%c", DOUBLE_VERTICAL );
                else
                    fprintf( Output, "%c", SINGLE_VERTICAL );
            }
        }
        fprintf( Output, "%c", DOUBLE_VERTICAL );
        fprintf( Output, "\n" );

        Cudd_RecursiveDeref( dd, CubeVerBDD );

        if ( v != nCellsVer-1 )
        // print separator line
        {
            for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
            if ( v&1 )
            {
                fprintf( Output, "%c", D_JOINS_D_VER_RIGHT );
                for ( s = 0; s < nCellsHor; s++ )
                {
                    fprintf( Output, "%c", DOUBLE_HORIZONTAL );
                    fprintf( Output, "%c", DOUBLE_HORIZONTAL );
                    fprintf( Output, "%c", DOUBLE_HORIZONTAL );
                    if ( s != nCellsHor-1 )
                    {
                        if ( s&1 )
                            fprintf( Output, "%c", DOUBLES_CROSS );
                        else
                            fprintf( Output, "%c", S_VER_CROSS_D_HOR );
                    }
                }
                fprintf( Output, "%c", D_JOINS_D_VER_LEFT );
            }
            else
            {
                fprintf( Output, "%c", S_JOINS_D_VER_RIGHT );
                for ( s = 0; s < nCellsHor; s++ )
                {
                    fprintf( Output, "%c", SINGLE_HORIZONTAL );
                    fprintf( Output, "%c", SINGLE_HORIZONTAL );
                    fprintf( Output, "%c", SINGLE_HORIZONTAL );
                    if ( s != nCellsHor-1 )
                    {
                        if ( s&1 )
                            fprintf( Output, "%c", S_HOR_CROSS_D_VER );
                        else
                            fprintf( Output, "%c", SINGLES_CROSS );
                    }
                }
                fprintf( Output, "%c", S_JOINS_D_VER_LEFT );
            }
            fprintf( Output, "\n" );
        }
    }
    
    ////////////////////////////////////////////////////////////////////
    // print the lower line
    for ( p = 0; p < nSkipSpaces; p++, fprintf( Output, " " ) );
    fprintf( Output, "%c", DOUBLE_BOT_LEFT );
    for ( s = 0; s < nCellsHor; s++ )
    {
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        fprintf( Output, "%c", DOUBLE_HORIZONTAL );
        if ( s != nCellsHor-1 )
        {
            if ( s&1 )
                fprintf( Output, "%c", D_JOINS_D_HOR_TOP );
            else
                fprintf( Output, "%c", S_JOINS_D_HOR_TOP );
        }
    }
    fprintf( Output, "%c", DOUBLE_BOT_RIGHT );
    fprintf( Output, "\n" );

    if ( !fHorizontalVarNamesPrintedAbove )
    {
        ////////////////////////////////////////////////////////////////////
        // print horizontal digits
        for ( d = 0; d < nVarsHor; d++ )
        {
            for ( p = 0; p < nSkipSpaces + 2; p++, fprintf( Output, " " ) );
            for ( n = 0; n < nCellsHor; n++ )
                if ( GrayCode(n) & (1<<(nVarsHor-1-d)) )
                    fprintf( Output, "1   " );
                else
                    fprintf( Output, "0   " );

            /////////////////////////////////
            fprintf( Output, "%c", (char)('a'+d) );
            /////////////////////////////////
            fprintf( Output, "\n" );
        }
    }
}



/*---------------------------------------------------------------------------*/
/* Definition of static functions                                            */
/*---------------------------------------------------------------------------*/

/**Function********************************************************************

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

******************************************************************************/
int GrayCode ( int BinCode )
{
  return BinCode ^ ( BinCode >> 1 );
}

/**Function********************************************************************

  Synopsis    []

  Description []

  SideEffects []

  SeeAlso     []

******************************************************************************/
int BinCode ( int GrayCode )
{
  int bc = GrayCode;
  while( GrayCode >>= 1 ) bc ^= GrayCode;
  return bc;
}


ABC_NAMESPACE_IMPL_END

