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

  FileName    [ifDec07.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [FPGA mapping based on priority cuts.]

  Synopsis    [Performs additional check.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - November 21, 2006.]

  Revision    [$Id: ifDec07.c,v 1.00 2006/11/21 00:00:00 alanmi Exp $]

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

#include "if.h"
#include "misc/extra/extra.h"
#include "bool/kit/kit.h"

ABC_NAMESPACE_IMPL_START


////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

// the bit count for the first 256 integer numbers
static int BitCount8[256] = {
    0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
    1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
    1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
    2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
    1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
    2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
    2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
    3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
// variable swapping code
static word PMasks[5][3] = {
    { ABC_CONST(0x9999999999999999), ABC_CONST(0x2222222222222222), ABC_CONST(0x4444444444444444) },
    { ABC_CONST(0xC3C3C3C3C3C3C3C3), ABC_CONST(0x0C0C0C0C0C0C0C0C), ABC_CONST(0x3030303030303030) },
    { ABC_CONST(0xF00FF00FF00FF00F), ABC_CONST(0x00F000F000F000F0), ABC_CONST(0x0F000F000F000F00) },
    { ABC_CONST(0xFF0000FFFF0000FF), ABC_CONST(0x0000FF000000FF00), ABC_CONST(0x00FF000000FF0000) },
    { ABC_CONST(0xFFFF00000000FFFF), ABC_CONST(0x00000000FFFF0000), ABC_CONST(0x0000FFFF00000000) }
};
// elementary truth tables
static word Truth6[6] = {
    ABC_CONST(0xAAAAAAAAAAAAAAAA),
    ABC_CONST(0xCCCCCCCCCCCCCCCC),
    ABC_CONST(0xF0F0F0F0F0F0F0F0),
    ABC_CONST(0xFF00FF00FF00FF00),
    ABC_CONST(0xFFFF0000FFFF0000),
    ABC_CONST(0xFFFFFFFF00000000)
};
static word Truth7[7][2] = {
    {ABC_CONST(0xAAAAAAAAAAAAAAAA),ABC_CONST(0xAAAAAAAAAAAAAAAA)},
    {ABC_CONST(0xCCCCCCCCCCCCCCCC),ABC_CONST(0xCCCCCCCCCCCCCCCC)},
    {ABC_CONST(0xF0F0F0F0F0F0F0F0),ABC_CONST(0xF0F0F0F0F0F0F0F0)},
    {ABC_CONST(0xFF00FF00FF00FF00),ABC_CONST(0xFF00FF00FF00FF00)},
    {ABC_CONST(0xFFFF0000FFFF0000),ABC_CONST(0xFFFF0000FFFF0000)},
    {ABC_CONST(0xFFFFFFFF00000000),ABC_CONST(0xFFFFFFFF00000000)},
    {ABC_CONST(0x0000000000000000),ABC_CONST(0xFFFFFFFFFFFFFFFF)}
};

extern void Kit_DsdPrintFromTruth( unsigned * pTruth, int nVars );
extern void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits );

////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////

void If_DecPrintConfig( word z )
{
   unsigned S[1];
   S[0] = (z & 0xffff) | ((z & 0xffff) << 16);
   Extra_PrintBinary( stdout, S, 16 ); 
   printf( " " );
   Kit_DsdPrintFromTruth( S, 4 );
   printf( " " );
   printf( " %d", (int)((z >> 16) & 7) );
   printf( " %d", (int)((z >> 20) & 7) );
   printf( " %d", (int)((z >> 24) & 7) );
   printf( " %d", (int)((z >> 28) & 7) );
   printf( "   " );
   S[0] = ((z >> 32) & 0xffff) | (((z >> 32) & 0xffff) << 16);
   Extra_PrintBinary( stdout, S, 16 );
   printf( " " );
   Kit_DsdPrintFromTruth( S, 4 );
   printf( " " );
   printf( " %d", (int)((z >> 48) & 7) );
   printf( " %d", (int)((z >> 52) & 7) );
   printf( " %d", (int)((z >> 56) & 7) );
   printf( " %d", (int)((z >> 60) & 7) );
   printf( "\n" );
}

// verification for 6-input function
static word If_Dec6ComposeLut4( int t, word f[4] )
{
    int m, v;
    word c, r = 0;
    for ( m = 0; m < 16; m++ )
    {
        if ( !((t >> m) & 1) )
            continue;
        c = ~(word)0;
        for ( v = 0; v < 4; v++ )
            c &= ((m >> v) & 1) ? f[v] : ~f[v];
        r |= c;
    }
    return r;
}
word If_Dec6Truth( word z )
{
    word r, q, f[4];
    int i, v;
    assert( z );
    for ( i = 0; i < 4; i++ )
    {
        v = (z >> (16+(i<<2))) & 7;
        assert( v != 7 );
        if ( v == 6 )
            continue;
        f[i] = Truth6[v];
    }
    q = If_Dec6ComposeLut4( (int)(z & 0xffff), f );
    for ( i = 0; i < 4; i++ )
    {
        v = (z >> (48+(i<<2))) & 7;
        if ( v == 6 )
            continue;
        f[i] = (v == 7) ? q : Truth6[v];
    }
    r = If_Dec6ComposeLut4( (int)((z >> 32) & 0xffff), f );
    return r;
}
void If_Dec6Verify( word t, word z )
{
    word r = If_Dec6Truth( z );
    if ( r != t )
	{
        If_DecPrintConfig( z );
        Kit_DsdPrintFromTruth( (unsigned*)&t, 6 ); printf( "\n" );
//        Kit_DsdPrintFromTruth( (unsigned*)&q, 6 ); printf( "\n" );
        Kit_DsdPrintFromTruth( (unsigned*)&r, 6 ); printf( "\n" );
        printf( "Verification failed!\n" );
	}
}
// verification for 7-input function
static void If_Dec7ComposeLut4( int t, word f[4][2], word r[2] )
{
    int m, v;
    word c[2];
    r[0] = r[1] = 0;
    for ( m = 0; m < 16; m++ )
    {
        if ( !((t >> m) & 1) )
            continue;
        c[0] = c[1] = ~(word)0;
        for ( v = 0; v < 4; v++ )
        {
            c[0] &= ((m >> v) & 1) ? f[v][0] : ~f[v][0];
            c[1] &= ((m >> v) & 1) ? f[v][1] : ~f[v][1];
        }
        r[0] |= c[0];
        r[1] |= c[1];
    }
}
void If_Dec7Verify( word t[2], word z )
{
    word f[4][2], r[2];
    int i, v;
    assert( z );
    for ( i = 0; i < 4; i++ )
    {
        v = (z >> (16+(i<<2))) & 7;
        f[i][0] = Truth7[v][0];
        f[i][1] = Truth7[v][1];
    }
    If_Dec7ComposeLut4( (int)(z & 0xffff), f, r );
    f[3][0] = r[0];
    f[3][1] = r[1];
    for ( i = 0; i < 3; i++ )
    {
        v = (z >> (48+(i<<2))) & 7;
        f[i][0] = Truth7[v][0];
        f[i][1] = Truth7[v][1];
    }
    If_Dec7ComposeLut4( (int)((z >> 32) & 0xffff), f, r );
    if ( r[0] != t[0] || r[1] != t[1] )
    {
        If_DecPrintConfig( z );
        Kit_DsdPrintFromTruth( (unsigned*)t, 7 ); printf( "\n" );
        Kit_DsdPrintFromTruth( (unsigned*)r, 7 ); printf( "\n" );
        printf( "Verification failed!\n" );
    }
}


// count the number of unique cofactors
static inline int If_Dec6CofCount2( word t )
{
    int i, Mask = 0;
    for ( i = 0; i < 16; i++ )
        Mask |= (1 << ((t >> (i<<2)) & 15));
    return BitCount8[((unsigned char*)&Mask)[0]] + BitCount8[((unsigned char*)&Mask)[1]];
}
// count the number of unique cofactors (up to 3)
static inline int If_Dec7CofCount3( word t[2] )
{
    unsigned char * pTruth = (unsigned char *)t;
    int i, iCof2 = 0;
    for ( i = 1; i < 16; i++ )
    {
        if ( pTruth[i] == pTruth[0] )
            continue;
        if ( iCof2 == 0 )
            iCof2 = i;
        else if ( pTruth[i] != pTruth[iCof2] )
            return 3;
    }
    assert( iCof2 );
    return 2;
}

// permute 6-input function
static inline word If_Dec6SwapAdjacent( word t, int v )
{
    assert( v < 5 );
    return (t & PMasks[v][0]) | ((t & PMasks[v][1]) << (1 << v)) | ((t & PMasks[v][2]) >> (1 << v));
}
static inline word If_Dec6MoveTo( word t, int v, int p, int Pla2Var[6], int Var2Pla[6] )
{
    int iPlace0, iPlace1;
    assert( Var2Pla[v] >= p );
    while ( Var2Pla[v] != p )
    {
        iPlace0 = Var2Pla[v]-1;
        iPlace1 = Var2Pla[v];
        t = If_Dec6SwapAdjacent( t, iPlace0 );
        Var2Pla[Pla2Var[iPlace0]]++;
        Var2Pla[Pla2Var[iPlace1]]--;
        Pla2Var[iPlace0] ^= Pla2Var[iPlace1];
        Pla2Var[iPlace1] ^= Pla2Var[iPlace0];
        Pla2Var[iPlace0] ^= Pla2Var[iPlace1];
    }
    assert( Pla2Var[p] == v );
    return t;
}

// permute 7-input function
static inline void If_Dec7SwapAdjacent( word t[2], int v )
{
    if ( v == 5 )
    {
        unsigned Temp = (t[0] >> 32);
        t[0]  = (t[0] & 0xFFFFFFFF) | ((t[1] & 0xFFFFFFFF) << 32);
        t[1] ^= (t[1] & 0xFFFFFFFF) ^ Temp;
        return;
    }
    assert( v < 5 );
    t[0] = If_Dec6SwapAdjacent( t[0], v );
    t[1] = If_Dec6SwapAdjacent( t[1], v );
}
static inline void If_Dec7MoveTo( word t[2], int v, int p, int Pla2Var[7], int Var2Pla[7] )
{
    int iPlace0, iPlace1;
    assert( Var2Pla[v] >= p );
    while ( Var2Pla[v] != p )
    {
        iPlace0 = Var2Pla[v]-1;
        iPlace1 = Var2Pla[v];
        If_Dec7SwapAdjacent( t, iPlace0 );
        Var2Pla[Pla2Var[iPlace0]]++;
        Var2Pla[Pla2Var[iPlace1]]--;
        Pla2Var[iPlace0] ^= Pla2Var[iPlace1];
        Pla2Var[iPlace1] ^= Pla2Var[iPlace0];
        Pla2Var[iPlace0] ^= Pla2Var[iPlace1];
    }
    assert( Pla2Var[p] == v );
}

// derive binary function
static inline int If_Dec6DeriveCount2( word t, int * pCof0, int * pCof1 )
{
    int i, Mask = 0;
	*pCof0 = (t & 15);
	*pCof1 = (t & 15);
    for ( i = 1; i < 16; i++ )
		if ( *pCof0 != ((t >> (i<<2)) & 15) )
		{
			*pCof1 = ((t >> (i<<2)) & 15);
			Mask |= (1 << i);
		}
	return Mask;
}
static inline int If_Dec7DeriveCount3( word t[2], int * pCof0, int * pCof1 )
{
    unsigned char * pTruth = (unsigned char *)t;
    int i, Mask = 0;
	*pCof0 = pTruth[0];
	*pCof1 = pTruth[0];
    for ( i = 1; i < 16; i++ )
		if ( *pCof0 != pTruth[i] )
		{
			*pCof1 = pTruth[i];
			Mask |= (1 << i);
		}
	return Mask;
}

// derives decomposition
static inline word If_Dec6Cofactor( word t, int iVar, int fCof1 )
{
    assert( iVar >= 0 && iVar < 6 );
    if ( fCof1 )
        return (t & Truth6[iVar]) | ((t & Truth6[iVar]) >> (1<<iVar));
    else
        return (t &~Truth6[iVar]) | ((t &~Truth6[iVar]) << (1<<iVar));
}
static word If_Dec6DeriveDisjoint( word t, int Pla2Var[6], int Var2Pla[6] )
{
	int i, Cof0, Cof1;
    word z = If_Dec6DeriveCount2( t, &Cof0, &Cof1 );
	for ( i = 0; i < 4; i++ )
		z |= (((word)Pla2Var[i+2]) << (16 + 4*i));
	z |= ((word)((Cof1 << 4) | Cof0) << 32);
	z |= ((word)((Cof1 << 4) | Cof0) << 40);
	for ( i = 0; i < 2; i++ )
		z |= (((word)Pla2Var[i]) << (48 + 4*i));
    z |= (((word)7) << (48 + 4*i++));
    assert( i == 3 );
    return z;
}
static word If_Dec6DeriveNonDisjoint( word t, int s, int Pla2Var0[6], int Var2Pla0[6] )
{
    word z, c0, c1;
	int Cof0[2], Cof1[2];
	int Truth0, Truth1, i;
    int Pla2Var[6], Var2Pla[6];
	assert( s >= 2 && s <= 5 );
    for ( i = 0; i < 6; i++ )
    {
        Pla2Var[i] = Pla2Var0[i];
        Var2Pla[i] = Var2Pla0[i];
    }
	for ( i = s; i < 5; i++ )
	{
        t = If_Dec6SwapAdjacent( t, i );
        Var2Pla[Pla2Var[i]]++;
        Var2Pla[Pla2Var[i+1]]--;
        Pla2Var[i] ^= Pla2Var[i+1];
        Pla2Var[i+1] ^= Pla2Var[i];
        Pla2Var[i] ^= Pla2Var[i+1];
	}
    c0 = If_Dec6Cofactor( t, 5, 0 );
    c1 = If_Dec6Cofactor( t, 5, 1 );
    assert( 2 >= If_Dec6CofCount2(c0) );
    assert( 2 >= If_Dec6CofCount2(c1) );
	Truth0 = If_Dec6DeriveCount2( c0, &Cof0[0], &Cof0[1] );
	Truth1 = If_Dec6DeriveCount2( c1, &Cof1[0], &Cof1[1] );
	z = ((Truth1 & 0xFF) << 8) | (Truth0 & 0xFF);
	for ( i = 0; i < 4; i++ )
		z |= (((word)Pla2Var[i+2]) << (16 + 4*i));
	z |= ((word)((Cof0[1] << 4) | Cof0[0]) << 32);
	z |= ((word)((Cof1[1] << 4) | Cof1[0]) << 40);
	for ( i = 0; i < 2; i++ )
		z |= (((word)Pla2Var[i]) << (48 + 4*i));
    z |= (((word)7) << (48 + 4*i++));
    z |= (((word)Pla2Var[5]) << (48 + 4*i++));
    assert( i == 4 );
    return z;
}
static word If_Dec7DeriveDisjoint( word t[2], int Pla2Var[7], int Var2Pla[7] )
{
	int i, Cof0, Cof1;
    word z = If_Dec7DeriveCount3( t, &Cof0, &Cof1 );
	for ( i = 0; i < 4; i++ )
		z |= (((word)Pla2Var[i+3]) << (16 + 4*i));
	z |= ((word)((Cof1 << 8) | Cof0) << 32);
	for ( i = 0; i < 3; i++ )
		z |= (((word)Pla2Var[i]) << (48 + 4*i));
	z |= (((word)7) << (48 + 4*i));
    return z;
}

static inline int If_Dec6CountOnes( word t )
{
    t =    (t & ABC_CONST(0x5555555555555555)) + ((t>> 1) & ABC_CONST(0x5555555555555555));
    t =    (t & ABC_CONST(0x3333333333333333)) + ((t>> 2) & ABC_CONST(0x3333333333333333));
    t =    (t & ABC_CONST(0x0F0F0F0F0F0F0F0F)) + ((t>> 4) & ABC_CONST(0x0F0F0F0F0F0F0F0F));
    t =    (t & ABC_CONST(0x00FF00FF00FF00FF)) + ((t>> 8) & ABC_CONST(0x00FF00FF00FF00FF));
    t =    (t & ABC_CONST(0x0000FFFF0000FFFF)) + ((t>>16) & ABC_CONST(0x0000FFFF0000FFFF));
    return (t & ABC_CONST(0x00000000FFFFFFFF)) +  (t>>32);
}
static inline int If_Dec6HasVar( word t, int v )
{
    return ((t & Truth6[v]) >> (1<<v)) != (t & ~Truth6[v]);
}
static inline int If_Dec7HasVar( word t[2], int v )
{
    assert( v >= 0 && v < 7 );
    if ( v == 6 )
        return t[0] != t[1]; 
    return ((t[0] & Truth6[v]) >> (1<<v)) != (t[0] & ~Truth6[v])
        || ((t[1] & Truth6[v]) >> (1<<v)) != (t[1] & ~Truth6[v]);
}

static inline void If_DecVerifyPerm( int Pla2Var[6], int Var2Pla[6] )
{
    int i;
    for ( i = 0; i < 6; i++ )
        assert( Pla2Var[Var2Pla[i]] == i );
} 
word If_Dec6Perform( word t, int fDerive )
{ 
	word r = 0;
    int i, v, u, x, Count, Pla2Var[6], Var2Pla[6];
    // start arrays
    for ( i = 0; i < 6; i++ )
    {
        assert( If_Dec6HasVar( t, i ) );
        Pla2Var[i] = Var2Pla[i] = i;
    }
    // generate permutations
    i = 0;
    for ( v = 0;   v < 6; v++ )
    for ( u = v+1; u < 6; u++, i++ )
    {
        t = If_Dec6MoveTo( t, v, 0, Pla2Var, Var2Pla );
        t = If_Dec6MoveTo( t, u, 1, Pla2Var, Var2Pla );
//        If_DecVerifyPerm( Pla2Var, Var2Pla );
        Count = If_Dec6CofCount2( t );
        assert( Count > 1 );
        if ( Count == 2 )
            return !fDerive ? 1 : If_Dec6DeriveDisjoint( t, Pla2Var, Var2Pla );
        // check non-disjoint decomposition
        if ( !r && (Count == 3 || Count == 4) )
        {
            for ( x = 0; x < 4; x++ )
            {
                word c0 = If_Dec6Cofactor( t, x+2, 0 );
                word c1 = If_Dec6Cofactor( t, x+2, 1 );
                if ( If_Dec6CofCount2( c0 ) <= 2 && If_Dec6CofCount2( c1 ) <= 2 )
                {
					r = !fDerive ? 1 : If_Dec6DeriveNonDisjoint( t, x+2, Pla2Var, Var2Pla );
					break;
                }
            }
        }
    }
    assert( i == 15 );
    return r;
}
word If_Dec7Perform( word t0[2], int fDerive )
{
    word t[2] = {t0[0], t0[1]}; 
    int i, v, u, y, Pla2Var[7], Var2Pla[7];
    // start arrays
    for ( i = 0; i < 7; i++ )
    {
/*
        if ( i < 6 )
            assert( If_Dec6HasVar( t[0], i ) || If_Dec6HasVar( t[1], i ) );
        else
            assert( t[0] != t[1] );
*/
        Pla2Var[i] = Var2Pla[i] = i;
    }
    // generate permutations
    for ( v = 0;   v < 7; v++ )
    for ( u = v+1; u < 7; u++ )
    for ( y = u+1; y < 7; y++ )
    {
        If_Dec7MoveTo( t, v, 0, Pla2Var, Var2Pla );
        If_Dec7MoveTo( t, u, 1, Pla2Var, Var2Pla );
        If_Dec7MoveTo( t, y, 2, Pla2Var, Var2Pla );
//        If_DecVerifyPerm( Pla2Var, Var2Pla );
        if ( If_Dec7CofCount3( t ) == 2 )
        {
            return !fDerive ? 1 : If_Dec7DeriveDisjoint( t, Pla2Var, Var2Pla );
        }
    }
    return 0;
}


// support minimization
static inline int If_DecSuppIsMinBase( int Supp )
{
    return (Supp & (Supp+1)) == 0;
}
static inline word If_Dec6TruthShrink( word uTruth, int nVars, int nVarsAll, unsigned Phase )
{
    int i, k, Var = 0;
    assert( nVarsAll <= 6 );
    for ( i = 0; i < nVarsAll; i++ )
        if ( Phase & (1 << i) )
        {
            for ( k = i-1; k >= Var; k-- )
                uTruth = If_Dec6SwapAdjacent( uTruth, k );
            Var++;
        }
    assert( Var == nVars );
    return uTruth;
}
word If_Dec6MinimumBase( word uTruth, int * pSupp, int nVarsAll, int * pnVars )
{
    int v, iVar = 0, uSupp = 0;
    assert( nVarsAll <= 6 );
    for ( v = 0; v < nVarsAll; v++ )
        if ( If_Dec6HasVar( uTruth, v ) )
        {
            uSupp |= (1 << v);
            if ( pSupp )
                pSupp[iVar] = pSupp[v];
            iVar++;
        }
    if ( pnVars )
        *pnVars = iVar;
    if ( If_DecSuppIsMinBase( uSupp ) )
        return uTruth;
    return If_Dec6TruthShrink( uTruth, iVar, nVarsAll, uSupp );
}

static inline void If_Dec7TruthShrink( word uTruth[2], int nVars, int nVarsAll, unsigned Phase )
{
    int i, k, Var = 0;
    assert( nVarsAll <= 7 );
    for ( i = 0; i < nVarsAll; i++ )
        if ( Phase & (1 << i) )
        {
            for ( k = i-1; k >= Var; k-- )
                If_Dec7SwapAdjacent( uTruth, k );
            Var++;
        }
    assert( Var == nVars );
}
void If_Dec7MinimumBase( word uTruth[2], int * pSupp, int nVarsAll, int * pnVars )
{
    int v, iVar = 0, uSupp = 0;
    assert( nVarsAll <= 7 );
    for ( v = 0; v < nVarsAll; v++ )
        if ( If_Dec7HasVar( uTruth, v ) )
        {
            uSupp |= (1 << v);
            if ( pSupp )
                pSupp[iVar] = pSupp[v];
            iVar++;
        }
    if ( pnVars )
        *pnVars = iVar;
    if ( If_DecSuppIsMinBase( uSupp ) )
        return;
    If_Dec7TruthShrink( uTruth, iVar, nVarsAll, uSupp );
}



// check for MUX decomposition
static inline int If_Dec6SuppSize( word t )
{
    int v, Count = 0;
    for ( v = 0; v < 6; v++ )
        if ( If_Dec6Cofactor(t, v, 0) != If_Dec6Cofactor(t, v, 1) )
            Count++;
    return Count;
}
static inline int If_Dec6CheckMux( word t )
{
    int v;
    for ( v = 0; v < 6; v++ )
        if ( If_Dec6SuppSize(If_Dec6Cofactor(t, v, 0)) < 5 &&
             If_Dec6SuppSize(If_Dec6Cofactor(t, v, 1)) < 5 )
             return v;
    return -1;
}

// check for MUX decomposition
static inline void If_Dec7Cofactor( word t[2], int iVar, int fCof1, word r[2] )
{
    assert( iVar >= 0 && iVar < 7 );
    if ( iVar == 6 )
    {
        if ( fCof1 )
            r[0] = r[1] = t[1];
        else
            r[0] = r[1] = t[0];
    }
    else
    {
        if ( fCof1 )
        {
            r[0] = (t[0] & Truth6[iVar]) | ((t[0] & Truth6[iVar]) >> (1<<iVar));
            r[1] = (t[1] & Truth6[iVar]) | ((t[1] & Truth6[iVar]) >> (1<<iVar));
        }
        else
        {
            r[0] = (t[0] &~Truth6[iVar]) | ((t[0] &~Truth6[iVar]) << (1<<iVar));
            r[1] = (t[1] &~Truth6[iVar]) | ((t[1] &~Truth6[iVar]) << (1<<iVar));
        }
    }
}
static inline int If_Dec7SuppSize( word t[2] )
{
    word c0[2], c1[2];
    int v, Count = 0;
    for ( v = 0; v < 7; v++ )
    {
        If_Dec7Cofactor( t, v, 0, c0 );
        If_Dec7Cofactor( t, v, 1, c1 );
        if ( c0[0] != c1[0] || c0[1] != c1[1] )
            Count++;
    }
    return Count;
}
static inline int If_Dec7CheckMux( word t[2] )
{
    word c0[2], c1[2];
    int v;
    for ( v = 0; v < 7; v++ )
    {
        If_Dec7Cofactor( t, v, 0, c0 );
        If_Dec7Cofactor( t, v, 1, c1 );
        if ( If_Dec7SuppSize(c0) < 5 && If_Dec7SuppSize(c1) < 5 )
            return v;
    }
    return -1;
}

// find the best MUX decomposition
int If_Dec6PickBestMux( word t, word Cofs[2] )
{
    int v, vBest = -1, Count0, Count1, CountBest = 1000;
    for ( v = 0; v < 6; v++ )
    {
        Count0 = If_Dec6SuppSize( If_Dec6Cofactor(t, v, 0) );
        Count1 = If_Dec6SuppSize( If_Dec6Cofactor(t, v, 1) );
        if ( Count0 < 5 && Count1 < 5 && CountBest > Count0 + Count1 )
        {
            CountBest = Count0 + Count1;
            vBest = v;
            Cofs[0] = If_Dec6Cofactor(t, v, 0);
            Cofs[1] = If_Dec6Cofactor(t, v, 1);
        }
    }
    return vBest;
}
int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
{
    word c0[2], c1[2];
    int v, vBest = -1, Count0, Count1, CountBest = 1000;
    for ( v = 0; v < 7; v++ )
    {
        If_Dec7Cofactor( t, v, 0, c0 );
        If_Dec7Cofactor( t, v, 1, c1 );
        Count0 = If_Dec7SuppSize(c0);
        Count1 = If_Dec7SuppSize(c1);
        if ( Count0 < 5 && Count1 < 5 && CountBest > Count0 + Count1 )
        {
            CountBest = Count0 + Count1;
            vBest = v;
            c0r[0] = c0[0]; c0r[1] = c0[1];
            c1r[0] = c1[0]; c1r[1] = c1[1];
        }
    }
    return vBest;
}



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

  Synopsis    [Checks decomposability ]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
// count the number of unique cofactors
static inline word If_Dec5CofCount2( word t, int x, int y, int * Pla2Var, word t0, int fDerive )
{
    int m, i, Mask;
    assert( x >= 0 && x < 4 );
    assert( y >= 0 && y < 4 );
    for ( m = 0; m < 4; m++ )
    {
        for ( Mask = i = 0; i < 16; i++ )
            if ( ((i >> x) & 1) == ((m >> 0) & 1) && ((i >> y) & 1) == ((m >> 1) & 1) )
                Mask |= (1 << ((t >> (i<<1)) & 3));
        if ( BitCount8[Mask & 0xF] > 2 )
            return 0;
    }
//    Kit_DsdPrintFromTruth( (unsigned *)&t, 5 ); printf( "\n" );
    if ( !fDerive )
        return 1;
    else
    {
        int fHas2, fHas3;
        // composition function C depends on {x, y, Out, v[0]}
        // decomposed function D depends on {x, y, z1, z2}
        word F[4] = { 0, ABC_CONST(0x5555555555555555), ABC_CONST(0xAAAAAAAAAAAAAAAA), ~((word)0) };
        word C2[4], D2[4] = {0}, C1[2], D1[2], C, D, z;
        int v, zz1 = -1, zz2 = -1;
        // find two variables
        for ( v = 0; v < 4; v++ )
            if ( v != x && v != y )
                {  zz1 = v; break; }
        for ( v = 1; v < 4; v++ )
            if ( v != x && v != y && v != zz1 )
                {  zz2 = v; break; }
        assert( zz1 != -1 && zz2 != -1 );
        // find the cofactors
        for ( m = 0; m < 4; m++ )
        {
            // for each cofactor, derive C2 and D2
            for ( Mask = i = 0; i < 16; i++ )
                if ( ((i >> x) & 1) == ((m >> 0) & 1) && ((i >> y) & 1) == ((m >> 1) & 1) )
                    Mask |= (1 << ((t >> (i<<1)) & 3));
            // find the values
            if ( BitCount8[Mask & 0xF] == 1 )
            {
                C2[m] = F[Abc_Tt6FirstBit( Mask )];
                D2[m] = ~(word)0;
            }
            else if ( BitCount8[Mask & 0xF] == 2 )
            {
                int Bit0 = Abc_Tt6FirstBit( Mask );
                int Bit1 = Abc_Tt6FirstBit( Mask ^ (((word)1)<<Bit0) );
                C2[m] = (F[Bit1] & Truth6[1]) | (F[Bit0] & ~Truth6[1]);
                // find Bit1 appears
                for ( Mask = i = 0; i < 16; i++ )
                    if ( ((i >> x) & 1) == ((m >> 0) & 1) && ((i >> y) & 1) == ((m >> 1) & 1) )
                        if ( Bit1 == ((t >> (i<<1)) & 3) )
                            D2[m] |= (((word)1) << ( (((i >> zz2) & 1) << 1) | ((i >> zz1) & 1) ));
            }
            else assert( 0 );
            D2[m] = Abc_Tt6Stretch( D2[m], 2 );
        }

        // combine
        C1[0] = (C2[1] & Truth6[2]) | (C2[0] & ~Truth6[2]);
        C1[1] = (C2[3] & Truth6[2]) | (C2[2] & ~Truth6[2]);
        C     = (C1[1] & Truth6[3]) | (C1[0] & ~Truth6[3]);

        // combine
        D1[0] = (D2[1] & Truth6[2]) | (D2[0] & ~Truth6[2]);
        D1[1] = (D2[3] & Truth6[2]) | (D2[2] & ~Truth6[2]);
        D     = (D1[1] & Truth6[3]) | (D1[0] & ~Truth6[3]);

//        printf( "\n" );
//        Kit_DsdPrintFromTruth( (unsigned *)&C, 5 ); printf("\n");
//        Kit_DsdPrintFromTruth( (unsigned *)&D, 5 ); printf("\n");

        // create configuration
        // find one
        fHas2 = Abc_TtHasVar(&D, 5, 2);
        fHas3 = Abc_TtHasVar(&D, 5, 3);
        if ( fHas2 && fHas3 )
        {
            z = D & 0xFFFF;
		    z |= (((word)Pla2Var[zz1+1]) << (16 + 4*0));
		    z |= (((word)Pla2Var[zz2+1]) << (16 + 4*1));
		    z |= (((word)Pla2Var[x+1])   << (16 + 4*2));
		    z |= (((word)Pla2Var[y+1])   << (16 + 4*3));
        }
        else if ( fHas2 && !fHas3 )
        {
            z = D & 0xFFFF;
		    z |= (((word)Pla2Var[zz1+1]) << (16 + 4*0));
		    z |= (((word)Pla2Var[zz2+1]) << (16 + 4*1));
		    z |= (((word)Pla2Var[x+1])   << (16 + 4*2));
		    z |= (((word)6)              << (16 + 4*3));
        }
        else if ( !fHas2 && fHas3 )
        {
            Abc_TtSwapVars( &D, 5, 2, 3 );
            z = D & 0xFFFF;
		    z |= (((word)Pla2Var[zz1+1]) << (16 + 4*0));
		    z |= (((word)Pla2Var[zz2+1]) << (16 + 4*1));
		    z |= (((word)Pla2Var[y+1])   << (16 + 4*2));
		    z |= (((word)6)              << (16 + 4*3));
        }
        else 
        {
            z = D & 0xFFFF;
		    z |= (((word)Pla2Var[zz1+1]) << (16 + 4*0));
		    z |= (((word)Pla2Var[zz2+1]) << (16 + 4*1));
		    z |= (((word)6)              << (16 + 4*2));
		    z |= (((word)6)              << (16 + 4*3));
        }

        // second one
        fHas2 = Abc_TtHasVar(&C, 5, 2);
        fHas3 = Abc_TtHasVar(&C, 5, 3);
        if ( fHas2 && fHas3 )
        {
	        z |= ((C & 0xFFFF) << 32);
		    z |= (((word)Pla2Var[0])     << (48 + 4*0));
		    z |= (((word)7)              << (48 + 4*1));
		    z |= (((word)Pla2Var[x+1])   << (48 + 4*2));
		    z |= (((word)Pla2Var[y+1])   << (48 + 4*3));
        }
        else if ( fHas2 && !fHas3 )
        {
	        z |= ((C & 0xFFFF) << 32);
		    z |= (((word)Pla2Var[0])     << (48 + 4*0));
		    z |= (((word)7)              << (48 + 4*1));
		    z |= (((word)Pla2Var[x+1])   << (48 + 4*2));
		    z |= (((word)6)              << (48 + 4*3));
        }
        else if ( !fHas2 && fHas3 )
        {
            Abc_TtSwapVars( &C, 5, 2, 3 );
	        z |= ((C & 0xFFFF) << 32);
		    z |= (((word)Pla2Var[0])     << (48 + 4*0));
		    z |= (((word)7)              << (48 + 4*1));
		    z |= (((word)Pla2Var[y+1])   << (48 + 4*2));
		    z |= (((word)6)              << (48 + 4*3));
        }
        else 
        {
	        z |= ((C & 0xFFFF) << 32);
		    z |= (((word)Pla2Var[0])     << (48 + 4*0));
		    z |= (((word)7)              << (48 + 4*1));
		    z |= (((word)6)              << (48 + 4*2));
		    z |= (((word)6)              << (48 + 4*3));
        }

        // verify
        {
            word t1 = If_Dec6Truth( z );
            if ( t1 != t0 )
            {
                printf( "\n" );
                Kit_DsdPrintFromTruth( (unsigned *)&C2[0], 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&C2[1], 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&C2[2], 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&C2[3], 5 ); printf("\n");

                printf( "\n" );
                Kit_DsdPrintFromTruth( (unsigned *)&D2[0], 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&D2[1], 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&D2[2], 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&D2[3], 5 ); printf("\n");

                printf( "\n" );
                Kit_DsdPrintFromTruth( (unsigned *)&C, 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&D, 5 ); printf("\n");

                printf( "\n" );
                Kit_DsdPrintFromTruth( (unsigned *)&t1, 5 ); printf("\n");
                Kit_DsdPrintFromTruth( (unsigned *)&t0, 5 ); printf("\n");
            }
            assert( t1 == t0 );
        }
        return z;
    }
}
word If_Dec5Perform( word t, int fDerive )
{
    int Pla2Var[7], Var2Pla[7];
    int i, j, v;
    word t0 = t;
/*
    word c0, c1, c00, c01, c10, c11;
    for ( i = 0; i < 5; i++ )
    {
        c0 = If_Dec6Cofactor( t, i, 0 );
        c1 = If_Dec6Cofactor( t, i, 1 );
        if ( c0 == 0 )
            return 1;
        if ( ~c0 == 0 )
            return 1;
        if ( c1 == 0 )
            return 1;
        if ( ~c1 == 0 )
            return 1;
       if ( c0 == ~c1 )
            return 1;
    }
    for ( i = 0; i < 4; i++ )
    {
        c0 = If_Dec6Cofactor( t, i, 0 );
        c1 = If_Dec6Cofactor( t, i, 1 );
        for ( j = i + 1; j < 5; j++ )
        {
            c00 = If_Dec6Cofactor( c0, j, 0 );
            c01 = If_Dec6Cofactor( c0, j, 1 );
            c10 = If_Dec6Cofactor( c1, j, 0 );
            c11 = If_Dec6Cofactor( c1, j, 1 );
            if ( c00 == c01 && c00 == c10 )
                return 1;
            if ( c11 == c01 && c11 == c10 )
                return 1;
            if ( c11 == c00 && c11 == c01 )
                return 1;
            if ( c11 == c00 && c11 == c10 )
                return 1;
            if ( c00 == c11 && c01 == c10 )
                return 1;
        }
    }
*/
    // start arrays
    for ( i = 0; i < 7; i++ )
        Pla2Var[i] = Var2Pla[i] = i;
    // generate permutations
    for ( v = 0; v < 5; v++ )
    {
        t = If_Dec6MoveTo( t, v, 0, Pla2Var, Var2Pla );
        If_DecVerifyPerm( Pla2Var, Var2Pla );
        for ( i = 0; i < 4; i++ )
            for ( j = i + 1; j < 4; j++ )
            {
                word z = If_Dec5CofCount2( t, i, j, Pla2Var, t0, fDerive );
                if ( z )
                {
/*
                    if ( v == 0 && i == 1 && j == 2 )
                    {
                          Kit_DsdPrintFromTruth( (unsigned *)&t, 5 ); printf( "\n" );
                    }
*/
                    return z;
                }
            }
    }

/*
    // start arrays
    for ( i = 0; i < 7; i++ )
        Pla2Var[i] = Var2Pla[i] = i;

    t = t0;
    for ( v = 0; v < 5; v++ )
    {
        int x, y;

        t = If_Dec6MoveTo( t, v, 0, Pla2Var, Var2Pla );
        If_DecVerifyPerm( Pla2Var, Var2Pla );

        for ( i = 0; i < 16; i++ )
            printf( "%d ", ((t >> (i<<1)) & 3) );
        printf( "\n" );

        for ( x = 0; x < 4; x++ )
        for ( y = x + 1; y < 4; y++ )
        {
            for ( i = 0; i < 16; i++ )
                if ( !((i >> x) & 1) && !((i >> y) & 1) )
                    printf( "%d ", ((t >> (i<<1)) & 3) );
            printf( "\n" );

            for ( i = 0; i < 16; i++ )
                if ( ((i >> x) & 1) && !((i >> y) & 1) )
                    printf( "%d ", ((t >> (i<<1)) & 3) );
            printf( "\n" );

            for ( i = 0; i < 16; i++ )
                if ( !((i >> x) & 1) && ((i >> y) & 1) )
                    printf( "%d ", ((t >> (i<<1)) & 3) );
            printf( "\n" );

            for ( i = 0; i < 16; i++ )
                if ( ((i >> x) & 1) && ((i >> y) & 1) )
                    printf( "%d ", ((t >> (i<<1)) & 3) );
            printf( "\n" );
            printf( "\n" );
        }
    }
*/

//    Kit_DsdPrintFromTruth( (unsigned *)&t, 5 ); printf( "\n" );
    return 0;
}

word If_Dec5PerformEx()
{
    word z;
    // find one
    z = (word)(0x17ac & 0xFFFF);
	z |= (((word)3) << (16 + 4*0));
	z |= (((word)4) << (16 + 4*1));
	z |= (((word)1) << (16 + 4*2));
	z |= (((word)2) << (16 + 4*3));
    // second one
	z |= (((word)(0x179a & 0xFFFF)) << 32);
	z |= (((word)0) << (48 + 4*0));
	z |= (((word)7) << (48 + 4*1));
	z |= (((word)1) << (48 + 4*2));
	z |= (((word)2) << (48 + 4*3));
    return z;
}
void If_Dec5PerformTest()
{
    word z, t, t1;
//    s = If_Dec5PerformEx();
//    t = If_Dec6Truth( s );
    t = 0xB0F3B0FFB0F3B0FF;

    Kit_DsdPrintFromTruth( (unsigned *)&t, 5 ); printf("\n");

    z = If_Dec5Perform( t, 1 );
    t1 = If_Dec6Truth( z );
    assert( t == t1 );
}


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

  Synopsis    [Performs additional check.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
word If_CutPerformDerive07( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr )
{
    if ( nLeaves < 5 )
        return 1;
    if ( nLeaves == 5 )
    {
        word z, t = ((word)pTruth[0] << 32) | (word)pTruth[0];
        z = If_Dec5Perform( t, 1 );
        If_Dec6Verify( t, z );
        return z;
    }
    if ( nLeaves == 6 )
    {
        word z, t = ((word *)pTruth)[0];
        z = If_Dec6Perform( t, 1 );
        If_Dec6Verify( t, z );
        return z;
    }
    if ( nLeaves == 7 )
    {
        word z, t[2];
        t[0] = ((word *)pTruth)[0];
        t[1] = ((word *)pTruth)[1];
        z = If_Dec7Perform( t, 1 );
        If_Dec7Verify( t, z );
        return z;
    }
    assert( 0 );
    return 0;
}

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

  Synopsis    [Performs additional check.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int If_CutPerformCheck07( If_Man_t * p, unsigned * pTruth, int nVars, int nLeaves, char * pStr )
{
	int fDerive = 0;
    int v;
    // skip non-support minimal
    for ( v = 0; v < nLeaves; v++ )
        if ( !Abc_TtHasVar( (word *)pTruth, nVars, v ) )
            return 0;
    // check
    if ( nLeaves < 5 )
        return 1;
    if ( nLeaves == 5 )
    {
        word z, t = ((word)pTruth[0] << 32) | (word)pTruth[0];
        z = If_Dec5Perform( t, fDerive );
        if ( fDerive && z )
            If_Dec6Verify( t, z );
        return z != 0;
    }
    if ( nLeaves == 6 )
    {
        word z, t = ((word *)pTruth)[0];
        z = If_Dec6Perform( t, fDerive );
        if ( fDerive && z )
        {
//            If_DecPrintConfig( z );
            If_Dec6Verify( t, z );
        }
//        if ( z == 0 )
//            Extra_PrintHex(stdout, (unsigned *)&t, 6), printf( "  " ), Kit_DsdPrintFromTruth( (unsigned *)&t, 6 ), printf( "\n" );
        return z != 0;
    }
    if ( nLeaves == 7 )
    {
        word z, t[2];
        t[0] = ((word *)pTruth)[0];
        t[1] = ((word *)pTruth)[1];
//        if ( If_Dec7CheckMux(t) >= 0 )
//            return 1;
        z = If_Dec7Perform( t, fDerive );
        if ( fDerive && z )
            If_Dec7Verify( t, z );
        return z != 0;
    }
    assert( 0 );
    return 0;
}

////////////////////////////////////////////////////////////////////////
///                       END OF FILE                                ///
////////////////////////////////////////////////////////////////////////


ABC_NAMESPACE_IMPL_END

