abcFx.c 44.2 KB
Newer Older
Alan Mishchenko committed
1 2 3 4 5 6 7 8
/**CFile****************************************************************

  FileName    [abcFx.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Network and node package.]

Alan Mishchenko committed
9
  Synopsis    [Implementation of traditional "fast_extract" algorithm.]
Alan Mishchenko committed
10

Alan Mishchenko committed
11
  Author      [Alan Mishchenko, Bruno Schmitt]
Alan Mishchenko committed
12
  
Alan Mishchenko committed
13
  Affiliation [UC Berkeley, UFRGS]
Alan Mishchenko committed
14 15 16 17 18 19 20 21 22 23 24

  Date        [Ver. 1.0. Started - April 26, 2013.]

  Revision    [$Id: abcFx.c,v 1.00 2013/04/26 00:00:00 alanmi Exp $]

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

#include "base/abc/abc.h"
#include "misc/vec/vecWec.h"
#include "misc/vec/vecQue.h"
#include "misc/vec/vecHsh.h"
25
#include "opt/fxch/Fxch.h"
Alan Mishchenko committed
26 27 28 29 30 31 32

ABC_NAMESPACE_IMPL_START

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

Alan Mishchenko committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
/*
    The code in this file implements the traditional "fast_extract" algorithm, 
    which extracts two-cube divisors concurrently with single-cube two-literal divisors,
    as proposed in the TCAD'92 paper by J. Rajski and J. Vasudevamurthi.

    Integration notes:

    It is assumed that each object (primary input or internal node) in the original network 
    is associated with a unique integer number, called object identifier (ObjId, for short).

    The user's input data given to 'fast_extract" is an array of cubes (pMan->vCubes).
    Each cube is an array of integers, in which the first entry contains ObjId of the node, 
    to which this cube belongs in the original network. The following entries of a cube are 
    SOP literals of this cube.  Each literal is represtned as 2*FaninId + ComplAttr, where FaninId 
    is ObjId of the fanin node and ComplAttr is 1 if literal is complemented, and 0 otherwise.

    The user's output data produced by 'fast_extract' is also an array of cubes (pMan->vCubes).
    If no divisors have been extracted, the output array is the same as the input array.
    If some divisors have been extracted, the output array contains updated old cubes and new cubes 
    representing the extracted divisors. The new divisors have their ObjId starting from the 
    largest ObjId used in the cubes. To give the user more flexibility, which may be needed when some 
    ObjIds are already used for primary output nodes, which do not participate in fast_extract,
    the parameter ObjIdMax is passed to procedure Fx_FastExtract().  The new divisors will receive
    their ObjId starting from ObjIdMax onward, as divisor extaction proceeds.

    The following two requirements are imposed on the input and output array of cubes:
    (1) The array of cubes should be sorted by the first entry in each cube (that is, cubes belonging 
    to the same node should form a contiguous range). 
    (2) Literals in a cube should be sorted in the increasing order of the integer numbers.
    
    To integrate this code into a calling application, such as ABC, the input cube array should 
    be generated (below this is done by the procedure Abc_NtkFxRetrieve) and the output cube array
    should be incorporated into the current network (below this is done by the procedure Abc_NtkFxInsert).
    In essence, the latter procedure performs the following:
    - removes the current fanins and SOPs of each node in the network
    - adds new nodes for each new divisor introduced by "fast_extract"
    - populates fanins and SOPs of each node, both old and new, as indicaded by the resulting cube array.

    Implementation notes:

    The implementation is optimized for simplicity and speed of computation.
    (1) Main input/output data-structure (pMan->vCubes) is the array of cubes which is dynamically updated by the algorithm.
    (2) Auxiliary data-structure (pMan->vLits) is the array of arrays. The i-th array contains IDs of cubes which have literal i.
    It may be convenient to think about the first (second) array as rows (columns) of a sparse matrix, 
    although the sparse matrix data-structure is not used in the proposed implementation.
    (3) Hash table (pMan->pHash) hashes the normalized divisors (represented as integer arrays) into integer numbers.
    (4) Array of divisor weights (pMan->vWeights), that is, the number of SOP literals to be saved by extacting each divisor.
    (5) Priority queue (pMan->vPrio), which sorts divisor (integer numbers) by their weight
    (6) Integer array (pMan->vVarCube), which maps each ObjId into the first cube of this object, 
    or -1, if there is no cubes as in the case of a primary input.

*/

Alan Mishchenko committed
86 87 88 89 90
typedef struct Fx_Man_t_ Fx_Man_t;
struct Fx_Man_t_
{
    // user's data
    Vec_Wec_t *     vCubes;     // cube -> lit
91
    int             LitCountMax;// max size of divisor to extract
92
    int             fCanonDivs; // use only AND/XOR/MUX
Alan Mishchenko committed
93 94
    // internal data
    Vec_Wec_t *     vLits;      // lit -> cube
Alan Mishchenko committed
95 96
    Vec_Int_t *     vCounts;    // literal counts (currently not used)
    Hsh_VecMan_t *  pHash;      // hash table for normalized divisors
Alan Mishchenko committed
97
    Vec_Flt_t *     vWeights;   // divisor weights
Alan Mishchenko committed
98 99
    Vec_Que_t *     vPrio;      // priority queue for divisors by weight
    Vec_Int_t *     vVarCube;   // mapping ObjId into its first cube
100
    Vec_Int_t *     vLevels;    // variable levels
Alan Mishchenko committed
101
    // temporary data to update the data-structure when a divisor is extracted
Alan Mishchenko committed
102 103
    Vec_Int_t *     vCubesS;    // single cubes for the given divisor
    Vec_Int_t *     vCubesD;    // cube pairs for the given divisor
Alan Mishchenko committed
104
    Vec_Int_t *     vCompls;    // complemented attribute of each cube pair
Alan Mishchenko committed
105
    Vec_Int_t *     vCubeFree;  // cube-free divisor
Alan Mishchenko committed
106
    Vec_Int_t *     vDiv;       // selected divisor
107
    Vec_Int_t *     vSCC;       // single cubes containment cubes
Alan Mishchenko committed
108
    // statistics 
109
    abctime         timeStart;  // starting time
Alan Mishchenko committed
110 111 112
    int             nVars;      // original problem variables
    int             nLits;      // the number of SOP literals
    int             nDivs;      // the number of extracted divisors
Alan Mishchenko committed
113
    int             nCompls;    // the number of complements
Alan Mishchenko committed
114 115 116 117 118
    int             nPairsS;    // number of lit pairs
    int             nPairsD;    // number of cube pairs
    int             nDivsS;     // single cube divisors
    int             nDivMux[3]; // 0 = mux, 1 = compl mux, 2 = no mux
};
Alan Mishchenko committed
119

Alan Mishchenko committed
120
static inline int Fx_ManGetFirstVarCube( Fx_Man_t * p, Vec_Int_t * vCube ) { return Vec_IntEntry( p->vVarCube, Vec_IntEntry(vCube, 0) ); }
Alan Mishchenko committed
121

Alan Mishchenko committed
122 123
#define Fx_ManForEachCubeVec( vVec, vCubes, vCube, i )           \
    for ( i = 0; (i < Vec_IntSize(vVec)) && ((vCube) = Vec_WecEntry(vCubes, Vec_IntEntry(vVec, i))); i++ )
Alan Mishchenko committed
124

Alan Mishchenko committed
125 126 127
////////////////////////////////////////////////////////////////////////
///                     FUNCTION DEFINITIONS                         ///
////////////////////////////////////////////////////////////////////////
Alan Mishchenko committed
128 129 130

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

Alan Mishchenko committed
131
  Synopsis    [Retrieves SOP information for fast_extract.]
Alan Mishchenko committed
132 133 134 135 136 137 138 139

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
140
Vec_Wec_t * Abc_NtkFxRetrieve( Abc_Ntk_t * pNtk )
Alan Mishchenko committed
141 142 143 144 145 146 147 148 149 150 151 152 153
{
    Vec_Wec_t * vCubes;
    Vec_Int_t * vCube;
    Abc_Obj_t * pNode;
    char * pCube, * pSop;
    int nVars, i, v, Lit;
    assert( Abc_NtkIsSopLogic(pNtk) );
    vCubes = Vec_WecAlloc( 1000 );
    Abc_NtkForEachNode( pNtk, pNode, i )
    {
        pSop = (char *)pNode->pData;
        nVars = Abc_SopGetVarNum(pSop);
        assert( nVars == Abc_ObjFaninNum(pNode) );
Alan Mishchenko committed
154
//        if ( nVars < 2 ) continue;
Alan Mishchenko committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
        Abc_SopForEachCube( pSop, nVars, pCube )
        {
            vCube = Vec_WecPushLevel( vCubes );
            Vec_IntPush( vCube, Abc_ObjId(pNode) );
            Abc_CubeForEachVar( pCube, Lit, v )
            {
                if ( Lit == '0' )
                    Vec_IntPush( vCube, Abc_Var2Lit(Abc_ObjFaninId(pNode, v), 1) );
                else if ( Lit == '1' )
                    Vec_IntPush( vCube, Abc_Var2Lit(Abc_ObjFaninId(pNode, v), 0) );
            }
            Vec_IntSelectSort( Vec_IntArray(vCube) + 1, Vec_IntSize(vCube) - 1 );
        }
    }
    return vCubes;
}

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

Alan Mishchenko committed
174
  Synopsis    [Inserts SOP information after fast_extract.]
Alan Mishchenko committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkFxInsert( Abc_Ntk_t * pNtk, Vec_Wec_t * vCubes )
{
    Vec_Int_t * vCube, * vPres, * vFirst, * vCount;
    Abc_Obj_t * pNode, * pFanin;
    char * pCube, * pSop;
    int i, k, v, Lit, iFanin, iNodeMax = 0;
    assert( Abc_NtkIsSopLogic(pNtk) );
    // check that cubes have no gaps and are ordered by first node
    Lit = -1;
    Vec_WecForEachLevel( vCubes, vCube, i )
    {
        assert( Vec_IntSize(vCube) > 0 );
        assert( Lit <= Vec_IntEntry(vCube, 0) );
        Lit = Vec_IntEntry(vCube, 0);
    }
    // find the largest index
    Vec_WecForEachLevel( vCubes, vCube, i )
        iNodeMax = Abc_MaxInt( iNodeMax, Vec_IntEntry(vCube, 0) );
Alan Mishchenko committed
201
    // quit if nothing changes
Alan Mishchenko committed
202 203
    if ( iNodeMax < Abc_NtkObjNumMax(pNtk) )
    {
Alan Mishchenko committed
204
        //printf( "The network is unchanged by fast extract.\n" );
Alan Mishchenko committed
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
        return;
    }
    // create new nodes
    for ( i = Abc_NtkObjNumMax(pNtk); i <= iNodeMax; i++ )
    {
        pNode = Abc_NtkCreateNode( pNtk );
        assert( i == (int)Abc_ObjId(pNode) );
    }
    // create node fanins
    vFirst = Vec_IntStart( Abc_NtkObjNumMax(pNtk) );
    vCount = Vec_IntStart( Abc_NtkObjNumMax(pNtk) );
    Vec_WecForEachLevel( vCubes, vCube, i )
    {
        iFanin = Vec_IntEntry( vCube, 0 );
        if ( Vec_IntEntry(vCount, iFanin) == 0 )
            Vec_IntWriteEntry( vFirst, iFanin, i );
        Vec_IntAddToEntry( vCount, iFanin, 1 );
    }
    // create node SOPs
    vPres = Vec_IntStartFull( Abc_NtkObjNumMax(pNtk) );
    Abc_NtkForEachNode( pNtk, pNode, i )
    {
Alan Mishchenko committed
227
//        if ( Vec_IntEntry(vCount, i) == 0 ) continue;
Alan Mishchenko committed
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
        Abc_ObjRemoveFanins( pNode );
        // create fanins
        assert( Vec_IntEntry(vCount, i) > 0 );
        for ( k = 0; k < Vec_IntEntry(vCount, i); k++ )
        {
            vCube = Vec_WecEntry( vCubes, Vec_IntEntry(vFirst, i) + k );
            assert( Vec_IntEntry( vCube, 0 ) == i );
            Vec_IntForEachEntryStart( vCube, Lit, v, 1 )
            {
                pFanin = Abc_NtkObj(pNtk, Abc_Lit2Var(Lit));
                if ( Vec_IntEntry(vPres, Abc_ObjId(pFanin)) >= 0 )
                    continue;
                Vec_IntWriteEntry(vPres, Abc_ObjId(pFanin), Abc_ObjFaninNum(pNode));
                Abc_ObjAddFanin( pNode, pFanin );
            }
        }
        // create SOP
Alan Mishchenko committed
245
        pSop = pCube = Abc_SopStart( (Mem_Flex_t *)pNtk->pManFunc, Vec_IntEntry(vCount, i), Abc_ObjFaninNum(pNode) );
Alan Mishchenko committed
246 247 248 249 250 251 252 253 254 255 256 257 258
        for ( k = 0; k < Vec_IntEntry(vCount, i); k++ )
        {
            vCube = Vec_WecEntry( vCubes, Vec_IntEntry(vFirst, i) + k );
            assert( Vec_IntEntry( vCube, 0 ) == i );
            Vec_IntForEachEntryStart( vCube, Lit, v, 1 )
            {
                pFanin = Abc_NtkObj(pNtk, Abc_Lit2Var(Lit));
                iFanin = Vec_IntEntry(vPres, Abc_ObjId(pFanin));
                assert( iFanin >= 0 && iFanin < Abc_ObjFaninNum(pNode) );
                pCube[iFanin] = Abc_LitIsCompl(Lit) ? '0' : '1';
            }
            pCube += Abc_ObjFaninNum(pNode) + 3;
        }
Alan Mishchenko committed
259
        // complement SOP if the original one was complemented
Alan Mishchenko committed
260
        if ( pNode->pData && Abc_SopIsComplement((char *)pNode->pData) )
Alan Mishchenko committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
            Abc_SopComplement( pSop );
        pNode->pData = pSop;
        // clean fanins
        Abc_ObjForEachFanin( pNode, pFanin, v )
            Vec_IntWriteEntry( vPres, Abc_ObjId(pFanin), -1 );
    }
    Vec_IntFree( vFirst );
    Vec_IntFree( vCount );
    Vec_IntFree( vPres );
}

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

  Synopsis    [Makes sure the nodes do not have complemented and duplicated fanins.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Abc_NtkFxCheck( Abc_Ntk_t * pNtk )
{
    Abc_Obj_t * pNode;
    int i;
//    Abc_NtkForEachObj( pNtk, pNode, i )
//        Abc_ObjPrint( stdout, pNode );
    Abc_NtkForEachNode( pNtk, pNode, i )
        if ( !Vec_IntCheckUniqueSmall( &pNode->vFanins ) )
            return 0;
    return 1;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
306
int Abc_NtkFxPerform( Abc_Ntk_t * pNtk, int nNewNodesMax, int LitCountMax, int fCanonDivs, int fVerbose, int fVeryVerbose )
Alan Mishchenko committed
307
{
308
    extern int Fx_FastExtract( Vec_Wec_t * vCubes, int ObjIdMax, int nNewNodesMax, int LitCountMax, int fCanonDivs, int fVerbose, int fVeryVerbose );
Alan Mishchenko committed
309 310 311 312 313 314 315 316 317
    Vec_Wec_t * vCubes;
    assert( Abc_NtkIsSopLogic(pNtk) );
    // check unique fanins
    if ( !Abc_NtkFxCheck(pNtk) )
    {
        printf( "Abc_NtkFastExtract: Nodes have duplicated fanins. FX is not performed.\n" );
        return 0;
    }
    // collect information about the covers
Alan Mishchenko committed
318
    vCubes = Abc_NtkFxRetrieve( pNtk );
Alan Mishchenko committed
319
    // call the fast extract procedure
320
    if ( Fx_FastExtract( vCubes, Abc_NtkObjNumMax(pNtk), nNewNodesMax, LitCountMax, fCanonDivs, fVerbose, fVeryVerbose ) > 0 )
Alan Mishchenko committed
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
    {
        // update the network
        Abc_NtkFxInsert( pNtk, vCubes );
        Vec_WecFree( vCubes );
        if ( !Abc_NtkCheck( pNtk ) )
            printf( "Abc_NtkFxPerform: The network check has failed.\n" );
        return 1;
    }
    else
        printf( "Warning: The network has not been changed by \"fx\".\n" );
    Vec_WecFree( vCubes );
    return 0;
}



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

Alan Mishchenko committed
339
  Synopsis    [Starting the manager.]
Alan Mishchenko committed
340 341 342 343 344 345 346 347

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
348
Fx_Man_t * Fx_ManStart( Vec_Wec_t * vCubes )
Alan Mishchenko committed
349
{
Alan Mishchenko committed
350 351 352 353 354 355 356 357 358
    Fx_Man_t * p;
    p = ABC_CALLOC( Fx_Man_t, 1 );
    p->vCubes   = vCubes;
    // temporary data
    p->vCubesS   = Vec_IntAlloc( 100 );
    p->vCubesD   = Vec_IntAlloc( 100 );
    p->vCompls   = Vec_IntAlloc( 100 );
    p->vCubeFree = Vec_IntAlloc( 100 );
    p->vDiv      = Vec_IntAlloc( 100 );
359
    p->vSCC      = Vec_IntAlloc( 100 );
Alan Mishchenko committed
360 361 362 363 364 365 366 367 368 369 370
    return p;
}
void Fx_ManStop( Fx_Man_t * p )
{
//    Vec_WecFree( p->vCubes );
    Vec_WecFree( p->vLits );
    Vec_IntFree( p->vCounts );
    Hsh_VecManStop( p->pHash );
    Vec_FltFree( p->vWeights );
    Vec_QueFree( p->vPrio );
    Vec_IntFree( p->vVarCube );
371
    Vec_IntFree( p->vLevels );
Alan Mishchenko committed
372 373 374 375 376 377
    // temporary data
    Vec_IntFree( p->vCubesS );
    Vec_IntFree( p->vCubesD );
    Vec_IntFree( p->vCompls );
    Vec_IntFree( p->vCubeFree );
    Vec_IntFree( p->vDiv );
378
    Vec_IntFree( p->vSCC );
Alan Mishchenko committed
379
    ABC_FREE( p );
Alan Mishchenko committed
380 381 382 383
}

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

384 385 386 387 388 389 390 391 392 393 394 395 396 397
  Synopsis    [Compute levels of the nodes.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static inline int Fx_ManComputeLevelDiv( Fx_Man_t * p, Vec_Int_t * vCubeFree )
{
    int i, Lit, Level = 0;
    Vec_IntForEachEntry( vCubeFree, Lit, i )
        Level = Abc_MaxInt( Level, Vec_IntEntry(p->vLevels, Abc_Lit2Var(Abc_Lit2Var(Lit))) );
398
    return Abc_MinInt( Level, 800 );
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
}
static inline int Fx_ManComputeLevelCube( Fx_Man_t * p, Vec_Int_t * vCube )
{
    int k, Lit, Level = 0;
    Vec_IntForEachEntryStart( vCube, Lit, k, 1 )
        Level = Abc_MaxInt( Level, Vec_IntEntry(p->vLevels, Abc_Lit2Var(Lit)) );
    return Level;
}
void Fx_ManComputeLevel( Fx_Man_t * p )
{
    Vec_Int_t * vCube;
    int i, iVar, iFirst = 0;
    iVar = Vec_IntEntry( Vec_WecEntry(p->vCubes,0), 0 );
    p->vLevels = Vec_IntStart( p->nVars );
    Vec_WecForEachLevel( p->vCubes, vCube, i )
    {
415 416 417 418 419 420 421 422
        if ( iVar != Vec_IntEntry(vCube, 0) )
        {
            // add the number of cubes
            Vec_IntAddToEntry( p->vLevels, iVar, i - iFirst );
            iVar = Vec_IntEntry(vCube, 0);
            iFirst = i;
        }
        Vec_IntUpdateEntry( p->vLevels, iVar, Fx_ManComputeLevelCube(p, vCube) );
423 424 425 426 427
    }
}

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

Alan Mishchenko committed
428
  Synopsis    [Printing procedures.]
Alan Mishchenko committed
429 430 431 432 433 434 435 436

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
437 438 439 440 441
static inline void Fx_PrintDivArray( Vec_Int_t * vDiv )
{
    int i, Lit;
    Vec_IntForEachEntry( vDiv, Lit, i )
        if ( !Abc_LitIsCompl(Lit) )
442
            printf( "%d(1)", Abc_Lit2Var(Lit) );
Alan Mishchenko committed
443 444 445
    printf( " + " );
    Vec_IntForEachEntry( vDiv, Lit, i )
        if ( Abc_LitIsCompl(Lit) )
446
            printf( "%d(2)", Abc_Lit2Var(Lit) );
Alan Mishchenko committed
447
}
Alan Mishchenko committed
448 449
static inline void Fx_PrintDiv( Fx_Man_t * p, int iDiv )
{
Alan Mishchenko committed
450 451 452
    int i;
    printf( "%4d : ", p->nDivs );
    printf( "Div %7d : ", iDiv );
453
    printf( "Weight %12.5f  ", Vec_FltEntry(p->vWeights, iDiv) );
454
    Fx_PrintDivArray( Hsh_VecReadEntry(p->pHash, iDiv) );
Alan Mishchenko committed
455
    for ( i = Vec_IntSize(Hsh_VecReadEntry(p->pHash, iDiv)) + 3; i < 16; i++ )
Alan Mishchenko committed
456 457 458
        printf( " " );
    printf( "Lits =%7d  ", p->nLits );
    printf( "Divs =%8d  ", Hsh_VecSize(p->pHash) );
459
    Abc_PrintTime( 1, "Time", Abc_Clock() - p->timeStart );
Alan Mishchenko committed
460 461 462 463 464 465 466
}
static void Fx_PrintDivisors( Fx_Man_t * p )
{
    int iDiv;
    for ( iDiv = 0; iDiv < Vec_FltSize(p->vWeights); iDiv++ )
        Fx_PrintDiv( p, iDiv );
}
467
static void Fx_PrintStats( Fx_Man_t * p, abctime clk )
Alan Mishchenko committed
468
{
469 470 471 472 473 474
    printf( "Cubes =%8d  ", Vec_WecSizeUsed(p->vCubes) );
    printf( "Lits  =%8d  ", Vec_WecSizeUsed(p->vLits) );
    printf( "Divs  =%8d  ", Hsh_VecSize(p->pHash) );
    printf( "Divs+ =%8d  ", Vec_QueSize(p->vPrio) );
    printf( "Compl =%8d  ", p->nDivMux[1] );
    printf( "Extr  =%7d  ", p->nDivs );
Alan Mishchenko committed
475 476 477 478 479
    Abc_PrintTime( 1, "Time", clk );
}

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

Alan Mishchenko committed
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
  Synopsis    [Returns 1 if the divisor should be complemented.]

  Description [Normalizes the divisor by putting, first, positive control 
  literal first and, second, positive data1 literal. As the result, 
  a MUX divisor is (ab + !ac) and an XOR divisor is (ab + !a!b).]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
static int Fx_ManDivNormalize( Vec_Int_t * vCubeFree ) // return 1 if complemented
{
    int * L = Vec_IntArray(vCubeFree);
    int RetValue = 0, LitA0 = -1, LitB0 = -1, LitA1 = -1, LitB1 = -1;
    assert( Vec_IntSize(vCubeFree) == 4 );
    if ( Abc_LitIsCompl(L[0]) != Abc_LitIsCompl(L[1]) && (L[0] >> 2) == (L[1] >> 2) ) // diff cubes, same vars
    {
        if ( Abc_LitIsCompl(L[2]) == Abc_LitIsCompl(L[3]) )
            return -1;
        LitA0 = Abc_Lit2Var(L[0]), LitB0 = Abc_Lit2Var(L[1]);
        if ( Abc_LitIsCompl(L[0]) == Abc_LitIsCompl(L[2]) )
        {
            assert( Abc_LitIsCompl(L[1]) == Abc_LitIsCompl(L[3]) );
            LitA1 = Abc_Lit2Var(L[2]), LitB1 = Abc_Lit2Var(L[3]);
        }
        else
        {
            assert( Abc_LitIsCompl(L[0]) == Abc_LitIsCompl(L[3]) );
            assert( Abc_LitIsCompl(L[1]) == Abc_LitIsCompl(L[2]) );
            LitA1 = Abc_Lit2Var(L[3]), LitB1 = Abc_Lit2Var(L[2]);
        }
    }
    else if ( Abc_LitIsCompl(L[1]) != Abc_LitIsCompl(L[2]) && (L[1] >> 2) == (L[2] >> 2) )
    {
        if ( Abc_LitIsCompl(L[0]) == Abc_LitIsCompl(L[3]) )
            return -1;
        LitA0 = Abc_Lit2Var(L[1]), LitB0 = Abc_Lit2Var(L[2]);
        if ( Abc_LitIsCompl(L[1]) == Abc_LitIsCompl(L[0]) )
            LitA1 = Abc_Lit2Var(L[0]), LitB1 = Abc_Lit2Var(L[3]);
        else
            LitA1 = Abc_Lit2Var(L[3]), LitB1 = Abc_Lit2Var(L[0]);
    }
    else if ( Abc_LitIsCompl(L[2]) != Abc_LitIsCompl(L[3]) && (L[2] >> 2) == (L[3] >> 2) )
    {
        if ( Abc_LitIsCompl(L[0]) == Abc_LitIsCompl(L[1]) )
            return -1;
        LitA0 = Abc_Lit2Var(L[2]), LitB0 = Abc_Lit2Var(L[3]);
        if ( Abc_LitIsCompl(L[2]) == Abc_LitIsCompl(L[0]) )
            LitA1 = Abc_Lit2Var(L[0]), LitB1 = Abc_Lit2Var(L[1]);
        else
            LitA1 = Abc_Lit2Var(L[1]), LitB1 = Abc_Lit2Var(L[0]);
    }
    else 
        return -1;
    assert( LitA0 == Abc_LitNot(LitB0) );
    if ( Abc_LitIsCompl(LitA0) )
    {
        ABC_SWAP( int, LitA0, LitB0 );
        ABC_SWAP( int, LitA1, LitB1 );
    }
    assert( !Abc_LitIsCompl(LitA0) );
    if ( Abc_LitIsCompl(LitA1) )
    {
        LitA1 = Abc_LitNot(LitA1);
        LitB1 = Abc_LitNot(LitB1);
        RetValue = 1;
    }
    assert( !Abc_LitIsCompl(LitA1) );
    // arrange literals in such as a way that
    // - the first two literals are control literals from different cubes
    // - the third literal is non-complented data input
    // - the forth literal is possibly complemented data input
    L[0] = Abc_Var2Lit( LitA0, 0 );
    L[1] = Abc_Var2Lit( LitB0, 1 );
    L[2] = Abc_Var2Lit( LitA1, 0 );
    L[3] = Abc_Var2Lit( LitB1, 1 );
    return RetValue;
}

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

  Synopsis    [Find a cube-free divisor of the two cubes.]
Alan Mishchenko committed
563 564 565 566 567 568 569 570

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
571
int Fx_ManDivFindCubeFree( Vec_Int_t * vArr1, Vec_Int_t * vArr2, Vec_Int_t * vCubeFree, int * fWarning )
Alan Mishchenko committed
572
{
573 574 575 576
    int * pBeg1 = Vec_IntArray( vArr1 ) + 1;  // skip variable ID
    int * pBeg2 = Vec_IntArray( vArr2 ) + 1;  // skip variable ID
    int * pEnd1 = Vec_IntLimit( vArr1 );
    int * pEnd2 = Vec_IntLimit( vArr2 );
Alan Mishchenko committed
577
    int Counter = 0, fAttr0 = 0, fAttr1 = 1;
Alan Mishchenko committed
578
    Vec_IntClear( vCubeFree );
Alan Mishchenko committed
579 580 581 582 583
    while ( pBeg1 < pEnd1 && pBeg2 < pEnd2 )
    {
        if ( *pBeg1 == *pBeg2 )
            pBeg1++, pBeg2++, Counter++;
        else if ( *pBeg1 < *pBeg2 )
Alan Mishchenko committed
584
            Vec_IntPush( vCubeFree, Abc_Var2Lit(*pBeg1++, fAttr0) );
585
        else  
Alan Mishchenko committed
586
        {
Alan Mishchenko committed
587
            if ( Vec_IntSize(vCubeFree) == 0 )
Alan Mishchenko committed
588
                fAttr0 = 1, fAttr1 = 0;
Alan Mishchenko committed
589
            Vec_IntPush( vCubeFree, Abc_Var2Lit(*pBeg2++, fAttr1) );
Alan Mishchenko committed
590 591 592
        }
    }
    while ( pBeg1 < pEnd1 )
Alan Mishchenko committed
593
        Vec_IntPush( vCubeFree, Abc_Var2Lit(*pBeg1++, fAttr0) );
Alan Mishchenko committed
594
    while ( pBeg2 < pEnd2 )
Alan Mishchenko committed
595
        Vec_IntPush( vCubeFree, Abc_Var2Lit(*pBeg2++, fAttr1) );
596 597 598
    if ( Vec_IntSize(vCubeFree) == 0 )
        printf( "The SOP has duplicated cubes.\n" );
    else if ( Vec_IntSize(vCubeFree) == 1 )
599
        return -1;
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
    else if ( Vec_IntSize( vCubeFree ) == 3 )
    {
        int * pArray = Vec_IntArray( vCubeFree ); 

        if ( Abc_Lit2Var( pArray[0] ) == Abc_LitNot( Abc_Lit2Var( pArray[1] ) ) )
        {
            if ( Abc_LitIsCompl( pArray[0] ) == Abc_LitIsCompl( pArray[2] ) )
                Vec_IntDrop( vCubeFree, 0 );
            else
                Vec_IntDrop( vCubeFree, 1 );
        }
        else if ( Abc_Lit2Var( pArray[1] ) == Abc_LitNot( Abc_Lit2Var( pArray[2] ) ) )
        {
            if ( Abc_LitIsCompl( pArray[1] ) == Abc_LitIsCompl( pArray[0] ) )
                Vec_IntDrop( vCubeFree, 1 );
            else
                Vec_IntDrop( vCubeFree, 2 );
        }

        if ( Vec_IntSize( vCubeFree ) == 2 )
        {
            int Lit0 = Abc_Lit2Var( pArray[0] ),
                Lit1 = Abc_Lit2Var( pArray[1] );

            if ( Lit0 > Lit1 )
                ABC_SWAP( int, Lit0, Lit1 );

            Vec_IntWriteEntry( vCubeFree, 0, Abc_Var2Lit( Lit0, 0 ) );
            Vec_IntWriteEntry( vCubeFree, 1, Abc_Var2Lit( Lit1, 1 ) );
        }
    }
Alan Mishchenko committed
631
    assert( !Abc_LitIsCompl(Vec_IntEntry(vCubeFree, 0)) );
Alan Mishchenko committed
632 633 634 635 636
    return Counter;
}

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

Alan Mishchenko committed
637
  Synopsis    [Procedures operating on a two-cube divisor.]
Alan Mishchenko committed
638 639 640 641 642 643 644 645

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
646
static inline void Fx_ManDivFindPivots( Vec_Int_t * vDiv, int * pLit0, int * pLit1 )
Alan Mishchenko committed
647
{
Alan Mishchenko committed
648 649 650 651
    int i, Lit;
    *pLit0 = -1;
    *pLit1 = -1;
    Vec_IntForEachEntry( vDiv, Lit, i )
Alan Mishchenko committed
652
    {
Alan Mishchenko committed
653 654 655 656 657 658 659 660 661 662 663 664
        if ( Abc_LitIsCompl(Lit) )
        {
            if ( *pLit1 == -1 )
                *pLit1 = Abc_Lit2Var(Lit);
        }
        else
        {
            if ( *pLit0 == -1 )
                *pLit0 = Abc_Lit2Var(Lit);
        }
        if ( *pLit0 >= 0 && *pLit1 >= 0 )
            return;
Alan Mishchenko committed
665 666
    }
}
Alan Mishchenko committed
667
static inline int Fx_ManDivRemoveLits( Vec_Int_t * vCube, Vec_Int_t * vDiv, int fCompl )
Alan Mishchenko committed
668
{
Alan Mishchenko committed
669
    int i, Lit, Count = 0;
Alan Mishchenko committed
670
    assert( !fCompl || Vec_IntSize(vDiv) == 4 );
Alan Mishchenko committed
671
    Vec_IntForEachEntry( vDiv, Lit, i )
672
    {
Alan Mishchenko committed
673
        Count += Vec_IntRemove1( vCube, Abc_Lit2Var(Lit) ^ (fCompl && i > 1) );  // the last two lits can be complemented
674 675 676
        if ( Vec_IntSize( vDiv ) == 2 )
            Count += Vec_IntRemove1( vCube, Abc_LitNot( Abc_Lit2Var(Lit) ) );
    }
Alan Mishchenko committed
677 678 679 680
    return Count;
}
static inline void Fx_ManDivAddLits( Vec_Int_t * vCube, Vec_Int_t * vCube2, Vec_Int_t * vDiv )
{
Alan Mishchenko committed
681
    int i, Lit, * pArray;
Alan Mishchenko committed
682 683 684 685 686 687 688
//    Vec_IntClear( vCube );
//    Vec_IntClear( vCube2 );
    Vec_IntForEachEntry( vDiv, Lit, i )
        if ( Abc_LitIsCompl(Lit) )
            Vec_IntPush( vCube2, Abc_Lit2Var(Lit) );
        else
            Vec_IntPush( vCube, Abc_Lit2Var(Lit) );
Alan Mishchenko committed
689 690 691 692 693 694 695 696 697 698
    if ( Vec_IntSize(vDiv) == 4 && Vec_IntSize(vCube) == 3 )
    {
        assert( Vec_IntSize(vCube2) == 3 );
        pArray = Vec_IntArray(vCube);
        if ( pArray[1] > pArray[2] )
            ABC_SWAP( int, pArray[1], pArray[2] );
        pArray = Vec_IntArray(vCube2);
        if ( pArray[1] > pArray[2] )
            ABC_SWAP( int, pArray[1], pArray[2] );
    }
Alan Mishchenko committed
699 700 701 702
}

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

Alan Mishchenko committed
703
  Synopsis    [Setting up the data-structure.]
Alan Mishchenko committed
704 705 706 707 708 709 710 711

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
712
void Fx_ManCreateLiterals( Fx_Man_t * p, int nVars )
Alan Mishchenko committed
713 714
{
    Vec_Int_t * vCube;
Alan Mishchenko committed
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
    int i, k, Lit, Count;
    // find the number of variables
    p->nVars = p->nLits = 0;
    Vec_WecForEachLevel( p->vCubes, vCube, i )
    {
        assert( Vec_IntSize(vCube) > 0 );
        p->nVars = Abc_MaxInt( p->nVars, Vec_IntEntry(vCube, 0) );
        p->nLits += Vec_IntSize(vCube) - 1;
        Vec_IntForEachEntryStart( vCube, Lit, k, 1 )
            p->nVars = Abc_MaxInt( p->nVars, Abc_Lit2Var(Lit) );
    }
//    p->nVars++;
    assert( p->nVars < nVars );
    p->nVars = nVars;
    // count literals
    p->vCounts = Vec_IntStart( 2*p->nVars );
    Vec_WecForEachLevel( p->vCubes, vCube, i )
        Vec_IntForEachEntryStart( vCube, Lit, k, 1 )
            Vec_IntAddToEntry( p->vCounts, Lit, 1 );
    // start literals
    p->vLits = Vec_WecStart( 2*p->nVars );
    Vec_IntForEachEntry( p->vCounts, Count, Lit )
        Vec_IntGrow( Vec_WecEntry(p->vLits, Lit), Count );
    // fill out literals
    Vec_WecForEachLevel( p->vCubes, vCube, i )
        Vec_IntForEachEntryStart( vCube, Lit, k, 1 )
            Vec_WecPush( p->vLits, Lit, i );
    // create mapping of variable into the first cube
    p->vVarCube = Vec_IntStartFull( p->nVars );
    Vec_WecForEachLevel( p->vCubes, vCube, i )
        if ( Vec_IntEntry(p->vVarCube, Vec_IntEntry(vCube, 0)) == -1 )
            Vec_IntWriteEntry( p->vVarCube, Vec_IntEntry(vCube, 0), i );
}
int Fx_ManCubeSingleCubeDivisors( Fx_Man_t * p, Vec_Int_t * vPivot, int fRemove, int fUpdate )
{
    int k, n, Lit, Lit2, iDiv;
    if ( Vec_IntSize(vPivot) < 2 )
        return 0;
    Vec_IntForEachEntryStart( vPivot, Lit, k, 1 )
    Vec_IntForEachEntryStart( vPivot, Lit2, n, k+1 )
    {
        assert( Lit < Lit2 );
Alan Mishchenko committed
757 758 759 760
        Vec_IntClear( p->vCubeFree );
        Vec_IntPush( p->vCubeFree, Abc_Var2Lit(Abc_LitNot(Lit), 0) );
        Vec_IntPush( p->vCubeFree, Abc_Var2Lit(Abc_LitNot(Lit2), 1) );
        iDiv = Hsh_VecManAdd( p->pHash, p->vCubeFree );
Alan Mishchenko committed
761 762 763 764
        if ( !fRemove )
        {
            if ( Vec_FltSize(p->vWeights) == iDiv )
            {
765
                Vec_FltPush(p->vWeights, -2 + 0.9 - 0.001 * Fx_ManComputeLevelDiv(p, p->vCubeFree));
Alan Mishchenko committed
766 767 768 769 770 771
                p->nDivsS++;
            }
            assert( iDiv < Vec_FltSize(p->vWeights) );
            Vec_FltAddToEntry( p->vWeights, iDiv, 1 );
            p->nPairsS++;
        }
Alan Mishchenko committed
772
        else
Alan Mishchenko committed
773 774 775 776 777 778 779 780 781 782 783 784 785 786
        {
            assert( iDiv < Vec_FltSize(p->vWeights) );
            Vec_FltAddToEntry( p->vWeights, iDiv, -1 );
            p->nPairsS--;
        }
        if ( fUpdate )
        {
            if ( Vec_QueIsMember(p->vPrio, iDiv) )
                Vec_QueUpdate( p->vPrio, iDiv );
            else if ( !fRemove )
                Vec_QuePush( p->vPrio, iDiv );
        }
    }
    return Vec_IntSize(vPivot) * (Vec_IntSize(vPivot) - 1) / 2;
Alan Mishchenko committed
787
}
788
void Fx_ManCubeDoubleCubeDivisors( Fx_Man_t * p, int iFirst, Vec_Int_t * vPivot, int fRemove, int fUpdate, int * fWarning )
Alan Mishchenko committed
789
{
Alan Mishchenko committed
790 791 792 793 794 795 796 797 798 799
    Vec_Int_t * vCube;
    int i, iDiv, Base;
    Vec_WecForEachLevelStart( p->vCubes, vCube, i, iFirst )
    {
        if ( Vec_IntSize(vCube) == 0 || vCube == vPivot )
            continue;
        if ( Vec_WecIntHasMark(vCube) && Vec_WecIntHasMark(vPivot) && vCube > vPivot )
            continue;
        if ( Vec_IntEntry(vCube, 0) != Vec_IntEntry(vPivot, 0) )
            break;
800
        Base = Fx_ManDivFindCubeFree( vCube, vPivot, p->vCubeFree, fWarning );
801 802 803 804 805 806 807 808 809 810 811
        if ( Base == -1 ) 
        {
            if ( fRemove == 0 )
            {
                if ( Vec_IntSize( vCube ) > Vec_IntSize( vPivot ) )
                    Vec_IntPush( p->vSCC, Vec_WecLevelId( p->vCubes, vCube ) );
                else
                    Vec_IntPush( p->vSCC, Vec_WecLevelId( p->vCubes, vPivot ) );
            }
            continue;
        }
Alan Mishchenko committed
812 813 814 815 816 817 818
        if ( Vec_IntSize(p->vCubeFree) == 4 )
        { 
            int Value = Fx_ManDivNormalize( p->vCubeFree );
            if ( Value == 0 )
                p->nDivMux[0]++;
            else if ( Value == 1 )
                p->nDivMux[1]++;
Alan Mishchenko committed
819
            else
Alan Mishchenko committed
820
                p->nDivMux[2]++;
821 822
            if ( p->fCanonDivs && Value < 0 )
                continue;
Alan Mishchenko committed
823
        }
824 825
        if ( p->LitCountMax && p->LitCountMax < Vec_IntSize(p->vCubeFree) )
            continue;
826 827
        if ( p->fCanonDivs && Vec_IntSize(p->vCubeFree) == 3 )
            continue;
Alan Mishchenko committed
828
        iDiv = Hsh_VecManAdd( p->pHash, p->vCubeFree );
Alan Mishchenko committed
829 830 831
        if ( !fRemove )
        {
            if ( iDiv == Vec_FltSize(p->vWeights) )
832
                Vec_FltPush(p->vWeights, -Vec_IntSize(p->vCubeFree) + 0.9 - 0.0009 * Fx_ManComputeLevelDiv(p, p->vCubeFree));
Alan Mishchenko committed
833
            assert( iDiv < Vec_FltSize(p->vWeights) );
Alan Mishchenko committed
834
            Vec_FltAddToEntry( p->vWeights, iDiv, Base + Vec_IntSize(p->vCubeFree) - 1 );
Alan Mishchenko committed
835 836 837 838 839
            p->nPairsD++;
        }
        else
        {
            assert( iDiv < Vec_FltSize(p->vWeights) );
Alan Mishchenko committed
840
            Vec_FltAddToEntry( p->vWeights, iDiv, -(Base + Vec_IntSize(p->vCubeFree) - 1) );
Alan Mishchenko committed
841 842 843 844 845 846 847 848 849
            p->nPairsD--;
        }
        if ( fUpdate )
        {
            if ( Vec_QueIsMember(p->vPrio, iDiv) )
                Vec_QueUpdate( p->vPrio, iDiv );
            else if ( !fRemove )
                Vec_QuePush( p->vPrio, iDiv );
        }
850
    } 
Alan Mishchenko committed
851 852 853 854 855
}
void Fx_ManCreateDivisors( Fx_Man_t * p )
{
    Vec_Int_t * vCube;
    float Weight;
856
    int i, fWarning = 0;
Alan Mishchenko committed
857 858 859 860 861 862 863 864 865 866
    // alloc hash table
    assert( p->pHash == NULL );
    p->pHash = Hsh_VecManStart( 1000 );
    p->vWeights = Vec_FltAlloc( 1000 );
    // create single-cube two-literal divisors
    Vec_WecForEachLevel( p->vCubes, vCube, i )
        Fx_ManCubeSingleCubeDivisors( p, vCube, 0, 0 ); // add - no update
    assert( p->nDivsS == Vec_FltSize(p->vWeights) );
    // create two-cube divisors
    Vec_WecForEachLevel( p->vCubes, vCube, i )
867
        Fx_ManCubeDoubleCubeDivisors( p, i+1, vCube, 0, 0, &fWarning ); // add - no update
Alan Mishchenko committed
868 869
    // create queue with all divisors
    p->vPrio = Vec_QueAlloc( Vec_FltSize(p->vWeights) );
870
    Vec_QueSetPriority( p->vPrio, Vec_FltArrayP(p->vWeights) );
Alan Mishchenko committed
871 872 873
    Vec_FltForEachEntry( p->vWeights, Weight, i )
        if ( Weight > 0.0 )
            Vec_QuePush( p->vPrio, i );
Alan Mishchenko committed
874 875 876 877 878
}


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

Alan Mishchenko committed
879
  Synopsis    [Compress the cubes by removing unused ones.]
Alan Mishchenko committed
880 881 882 883 884 885 886 887

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
888
static inline void Fx_ManCompressCubes( Vec_Wec_t * vCubes, Vec_Int_t * vLit2Cube )
Alan Mishchenko committed
889
{
Alan Mishchenko committed
890 891 892 893 894
    int i, CubeId, k = 0;
    Vec_IntForEachEntry( vLit2Cube, CubeId, i )
        if ( Vec_IntSize(Vec_WecEntry(vCubes, CubeId)) > 0 )
            Vec_IntWriteEntry( vLit2Cube, k++, CubeId );
    Vec_IntShrink( vLit2Cube, k );
Alan Mishchenko committed
895 896
}

Alan Mishchenko committed
897

Alan Mishchenko committed
898 899
/**Function*************************************************************

Alan Mishchenko committed
900
  Synopsis    [Find command cube pairs.]
Alan Mishchenko committed
901 902 903 904 905 906 907 908

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Alan Mishchenko committed
909
static inline int Fx_ManGetCubeVar( Vec_Wec_t * vCubes, int iCube )  { return Vec_IntEntry( Vec_WecEntry(vCubes, iCube), 0 );      }
910
void Fx_ManFindCommonPairs( Vec_Wec_t * vCubes, Vec_Int_t * vPart0, Vec_Int_t * vPart1, Vec_Int_t * vPairs, Vec_Int_t * vCompls, Vec_Int_t * vDiv, Vec_Int_t * vCubeFree, int * fWarning )
Alan Mishchenko committed
911 912 913 914 915
{
    int * pBeg1 = vPart0->pArray;
    int * pBeg2 = vPart1->pArray;
    int * pEnd1 = vPart0->pArray + vPart0->nSize;
    int * pEnd2 = vPart1->pArray + vPart1->nSize;
Alan Mishchenko committed
916
    int i, k, i_, k_, fCompl, CubeId1, CubeId2;
Alan Mishchenko committed
917
    Vec_IntClear( vPairs );
Alan Mishchenko committed
918
    Vec_IntClear( vCompls );
Alan Mishchenko committed
919
    while ( pBeg1 < pEnd1 && pBeg2 < pEnd2 )
Alan Mishchenko committed
920
    {
Alan Mishchenko committed
921 922
        CubeId1 = Fx_ManGetCubeVar(vCubes, *pBeg1);
        CubeId2 = Fx_ManGetCubeVar(vCubes, *pBeg2);
Alan Mishchenko committed
923
        if ( CubeId1 == CubeId2 )
Alan Mishchenko committed
924
        {
Alan Mishchenko committed
925 926 927 928 929 930 931 932 933 934 935
            for ( i = 1; pBeg1+i < pEnd1; i++ )
                if ( CubeId1 != Fx_ManGetCubeVar(vCubes, pBeg1[i]) )
                    break;
            for ( k = 1; pBeg2+k < pEnd2; k++ )
                if ( CubeId1 != Fx_ManGetCubeVar(vCubes, pBeg2[k]) )
                    break;
            for ( i_ = 0; i_ < i; i_++ )
            for ( k_ = 0; k_ < k; k_++ )
            {
                if ( pBeg1[i_] == pBeg2[k_] )
                    continue;
936
                Fx_ManDivFindCubeFree( Vec_WecEntry(vCubes, pBeg1[i_]), Vec_WecEntry(vCubes, pBeg2[k_]), vCubeFree, fWarning );
Alan Mishchenko committed
937 938
                fCompl = (Vec_IntSize(vCubeFree) == 4 && Fx_ManDivNormalize(vCubeFree) == 1);
                if ( !Vec_IntEqual( vDiv, vCubeFree ) )
Alan Mishchenko committed
939 940 941
                    continue;
                Vec_IntPush( vPairs, pBeg1[i_] );
                Vec_IntPush( vPairs, pBeg2[k_] );
Alan Mishchenko committed
942
                Vec_IntPush( vCompls, fCompl );
Alan Mishchenko committed
943 944 945
            }
            pBeg1 += i;
            pBeg2 += k;
Alan Mishchenko committed
946
        }
Alan Mishchenko committed
947 948 949 950
        else if ( CubeId1 < CubeId2 )
            pBeg1++;
        else 
            pBeg2++;
Alan Mishchenko committed
951 952
    }
}
Alan Mishchenko committed
953 954 955

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

Alan Mishchenko committed
956
  Synopsis    [Updates the data-structure when one divisor is selected.]
Alan Mishchenko committed
957 958 959 960 961 962 963 964

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
965
void Fx_ManUpdate( Fx_Man_t * p, int iDiv, int * fWarning )
Alan Mishchenko committed
966
{
Alan Mishchenko committed
967
    Vec_Int_t * vCube, * vCube2, * vLitP = NULL, * vLitN = NULL;
Alan Mishchenko committed
968
    Vec_Int_t * vDiv = p->vDiv;
969
    int i, k, Lit0, Lit1, iVarNew = 0, RetValue, Level;
970 971
    float Diff = Vec_FltEntry(p->vWeights, iDiv) - (float)((int)Vec_FltEntry(p->vWeights, iDiv));
    assert( Diff > 0.0 && Diff < 1.0 );
Alan Mishchenko committed
972 973 974

    // get the divisor and select pivot variables
    p->nDivs++;
Alan Mishchenko committed
975 976 977 978 979
    Vec_IntClear( vDiv );
    Vec_IntAppend( vDiv, Hsh_VecReadEntry(p->pHash, iDiv) );
    Fx_ManDivFindPivots( vDiv, &Lit0, &Lit1 );
    assert( Lit0 >= 0 && Lit1 >= 0 );

980

Alan Mishchenko committed
981 982 983 984 985 986 987 988 989 990 991 992
    // collect single-cube-divisor cubes
    Vec_IntClear( p->vCubesS );
    if ( Vec_IntSize(vDiv) == 2 )
    {
        Fx_ManCompressCubes( p->vCubes, Vec_WecEntry(p->vLits, Abc_LitNot(Lit0)) );
        Fx_ManCompressCubes( p->vCubes, Vec_WecEntry(p->vLits, Abc_LitNot(Lit1)) );
        Vec_IntTwoRemoveCommon( Vec_WecEntry(p->vLits, Abc_LitNot(Lit0)), Vec_WecEntry(p->vLits, Abc_LitNot(Lit1)), p->vCubesS );
    }

    // collect double-cube-divisor cube pairs
    Fx_ManCompressCubes( p->vCubes, Vec_WecEntry(p->vLits, Lit0) );
    Fx_ManCompressCubes( p->vCubes, Vec_WecEntry(p->vLits, Lit1) );
993
    Fx_ManFindCommonPairs( p->vCubes, Vec_WecEntry(p->vLits, Lit0), Vec_WecEntry(p->vLits, Lit1), p->vCubesD, p->vCompls, vDiv, p->vCubeFree, fWarning );
Alan Mishchenko committed
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006

    // subtract cost of single-cube divisors
    Fx_ManForEachCubeVec( p->vCubesS, p->vCubes, vCube, i )
        Fx_ManCubeSingleCubeDivisors( p, vCube, 1, 1 );  // remove - update
    Fx_ManForEachCubeVec( p->vCubesD, p->vCubes, vCube, i )
        Fx_ManCubeSingleCubeDivisors( p, vCube, 1, 1 );  // remove - update

    // mark the cubes to be removed
    Vec_WecMarkLevels( p->vCubes, p->vCubesS );
    Vec_WecMarkLevels( p->vCubes, p->vCubesD );

    // subtract cost of double-cube divisors
    Fx_ManForEachCubeVec( p->vCubesS, p->vCubes, vCube, i )
1007
        Fx_ManCubeDoubleCubeDivisors( p, Fx_ManGetFirstVarCube(p, vCube), vCube, 1, 1, fWarning );  // remove - update
Alan Mishchenko committed
1008
    Fx_ManForEachCubeVec( p->vCubesD, p->vCubes, vCube, i )
1009
        Fx_ManCubeDoubleCubeDivisors( p, Fx_ManGetFirstVarCube(p, vCube), vCube, 1, 1, fWarning );  // remove - update
Alan Mishchenko committed
1010 1011 1012 1013 1014

    // unmark the cubes to be removed
    Vec_WecUnmarkLevels( p->vCubes, p->vCubesS );
    Vec_WecUnmarkLevels( p->vCubes, p->vCubesD );

1015 1016 1017
    if ( Abc_Lit2Var(Lit0) == Abc_Lit2Var(Lit1) && Vec_IntSize(Hsh_VecReadEntry(p->pHash, iDiv)) == 2 )
        goto ExtractFromPairs;

Alan Mishchenko committed
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
    // create new divisor
    iVarNew = Vec_WecSize( p->vLits ) / 2;
    assert( Vec_IntSize(p->vVarCube) == iVarNew );
    Vec_IntPush( p->vVarCube, Vec_WecSize(p->vCubes) );
    vCube = Vec_WecPushLevel( p->vCubes );
    Vec_IntPush( vCube, iVarNew );
    if ( Vec_IntSize(vDiv) == 2 )
    {
        Vec_IntPush( vCube, Abc_LitNot(Lit0) );
        Vec_IntPush( vCube, Abc_LitNot(Lit1) );
1028
        Level = 1 + Fx_ManComputeLevelCube( p, vCube );
Alan Mishchenko committed
1029 1030 1031 1032 1033 1034 1035
    }
    else
    {
        vCube2 = Vec_WecPushLevel( p->vCubes );
        vCube = Vec_WecEntry( p->vCubes, Vec_WecSize(p->vCubes) - 2 );
        Vec_IntPush( vCube2, iVarNew );
        Fx_ManDivAddLits( vCube, vCube2, vDiv );
1036
        Level = 2 + Abc_MaxInt( Fx_ManComputeLevelCube(p, vCube), Fx_ManComputeLevelCube(p, vCube2) );
Alan Mishchenko committed
1037
    }
1038 1039
    assert( Vec_IntSize(p->vLevels) == iVarNew );
    Vec_IntPush( p->vLevels, Level );
Alan Mishchenko committed
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
    // do not add new cubes to the matrix 
    p->nLits += Vec_IntSize( vDiv );
    // create new literals
    vLitP = Vec_WecPushLevel( p->vLits );
    vLitN = Vec_WecPushLevel( p->vLits );
    vLitP = Vec_WecEntry( p->vLits, Vec_WecSize(p->vLits) - 2 );
    // create updated single-cube divisor cubes
    Fx_ManForEachCubeVec( p->vCubesS, p->vCubes, vCube, i )
    {
        RetValue  = Vec_IntRemove1( vCube, Abc_LitNot(Lit0) );
        RetValue += Vec_IntRemove1( vCube, Abc_LitNot(Lit1) );
        assert( RetValue == 2 );
        Vec_IntPush( vCube, Abc_Var2Lit(iVarNew, 0) );
        Vec_IntPush( vLitP, Vec_WecLevelId(p->vCubes, vCube) );
        p->nLits--;
    }
    // create updated double-cube divisor cube pairs
1057
ExtractFromPairs:
Alan Mishchenko committed
1058
    k = 0;
Alan Mishchenko committed
1059
    p->nCompls = 0;
Alan Mishchenko committed
1060
    assert( Vec_IntSize(p->vCubesD) % 2 == 0 );
Alan Mishchenko committed
1061 1062
    assert( Vec_IntSize(p->vCubesD) == 2 * Vec_IntSize(p->vCompls) );
    for ( i = 0; i < Vec_IntSize(p->vCubesD); i += 2 )
Alan Mishchenko committed
1063
    {
Alan Mishchenko committed
1064
        int fCompl = Vec_IntEntry(p->vCompls, i/2);
Alan Mishchenko committed
1065
        p->nCompls += fCompl;
Alan Mishchenko committed
1066 1067 1068 1069
        vCube  = Vec_WecEntry( p->vCubes, Vec_IntEntry(p->vCubesD, i) );
        vCube2 = Vec_WecEntry( p->vCubes, Vec_IntEntry(p->vCubesD, i+1) );
        RetValue  = Fx_ManDivRemoveLits( vCube, vDiv, fCompl );  // cube 2*i
        RetValue += Fx_ManDivRemoveLits( vCube2, vDiv, fCompl ); // cube 2*i+1
1070 1071
        assert( RetValue == Vec_IntSize(vDiv) || RetValue == Vec_IntSize( vDiv ) + 1);
        if ( iVarNew > 0 )
Alan Mishchenko committed
1072
        {
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
            if ( Vec_IntSize(vDiv) == 2 || fCompl )
            {
                Vec_IntPush( vCube, Abc_Var2Lit(iVarNew, 1) );
                Vec_IntPush( vLitN, Vec_WecLevelId(p->vCubes, vCube) ); // MAKE SURE vCube IS SORTED BY ID
            }
            else 
            {
                Vec_IntPush( vCube, Abc_Var2Lit(iVarNew, 0) );
                Vec_IntPush( vLitP, Vec_WecLevelId(p->vCubes, vCube) ); // MAKE SURE vCube IS SORTED BY ID
            }
Alan Mishchenko committed
1083 1084
        }
        p->nLits -= Vec_IntSize(vDiv) + Vec_IntSize(vCube2) - 2;
1085

Alan Mishchenko committed
1086 1087 1088 1089 1090 1091 1092
        // remove second cube
        Vec_IntWriteEntry( p->vCubesD, k++, Vec_WecLevelId(p->vCubes, vCube) );
        Vec_IntClear( vCube2 ); 
    }
    assert( k == Vec_IntSize(p->vCubesD) / 2 );
    Vec_IntShrink( p->vCubesD, k );
    Vec_IntSort( p->vCubesD, 0 );
1093 1094
    //Vec_IntSort( vLitN, 0 );
    //Vec_IntSort( vLitP, 0 );
Alan Mishchenko committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107

    // add cost of single-cube divisors
    Fx_ManForEachCubeVec( p->vCubesS, p->vCubes, vCube, i )
        Fx_ManCubeSingleCubeDivisors( p, vCube, 0, 1 );  // add - update
    Fx_ManForEachCubeVec( p->vCubesD, p->vCubes, vCube, i )
        Fx_ManCubeSingleCubeDivisors( p, vCube, 0, 1 );  // add - update

    // mark the cubes to be removed
    Vec_WecMarkLevels( p->vCubes, p->vCubesS );
    Vec_WecMarkLevels( p->vCubes, p->vCubesD );

    // add cost of double-cube divisors
    Fx_ManForEachCubeVec( p->vCubesS, p->vCubes, vCube, i )
1108
        Fx_ManCubeDoubleCubeDivisors( p, Fx_ManGetFirstVarCube(p, vCube), vCube, 0, 1, fWarning );  // add - update
Alan Mishchenko committed
1109
    Fx_ManForEachCubeVec( p->vCubesD, p->vCubes, vCube, i )
1110
        Fx_ManCubeDoubleCubeDivisors( p, Fx_ManGetFirstVarCube(p, vCube), vCube, 0, 1, fWarning );  // add - update
Alan Mishchenko committed
1111 1112 1113 1114 1115

    // unmark the cubes to be removed
    Vec_WecUnmarkLevels( p->vCubes, p->vCubesS );
    Vec_WecUnmarkLevels( p->vCubes, p->vCubesD );

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
    // Deal with SCC
    if ( Vec_IntSize( p->vSCC ) )
    {
        Vec_IntUniqify( p->vSCC );
        Fx_ManForEachCubeVec( p->vSCC, p->vCubes, vCube, i )
        {
            Fx_ManCubeDoubleCubeDivisors( p, Fx_ManGetFirstVarCube(p, vCube), vCube, 1, 1, fWarning );  // remove - update
            Vec_IntClear( vCube );
        }
        Vec_IntClear( p->vSCC );
    }
Alan Mishchenko committed
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
    // add cost of the new divisor
    if ( Vec_IntSize(vDiv) > 2 )
    {
        vCube  = Vec_WecEntry( p->vCubes, Vec_WecSize(p->vCubes) - 2 );
        vCube2 = Vec_WecEntry( p->vCubes, Vec_WecSize(p->vCubes) - 1 );
        Fx_ManCubeSingleCubeDivisors( p, vCube,  0, 1 );  // add - update
        Fx_ManCubeSingleCubeDivisors( p, vCube2, 0, 1 );  // add - update
        Vec_IntForEachEntryStart( vCube, Lit0, i, 1 )
            Vec_WecPush( p->vLits, Lit0, Vec_WecLevelId(p->vCubes, vCube) );
        Vec_IntForEachEntryStart( vCube2, Lit0, i, 1 )
            Vec_WecPush( p->vLits, Lit0, Vec_WecLevelId(p->vCubes, vCube2) );
    }

    // remove these cubes from the lit array of the divisor
    Vec_IntForEachEntry( vDiv, Lit0, i )
Alan Mishchenko committed
1142
    {
Alan Mishchenko committed
1143
        Vec_IntTwoRemove( Vec_WecEntry(p->vLits, Abc_Lit2Var(Lit0)), p->vCubesD );
1144
        if ( (p->nCompls && i > 1) || Vec_IntSize( vDiv ) == 2 ) // the last two lits are possibly complemented
Alan Mishchenko committed
1145 1146
            Vec_IntTwoRemove( Vec_WecEntry(p->vLits, Abc_LitNot(Abc_Lit2Var(Lit0))), p->vCubesD );
    }
1147

Alan Mishchenko committed
1148 1149 1150 1151
}

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

Alan Mishchenko committed
1152
  Synopsis    [Implements the traditional fast_extract algorithm.]
Alan Mishchenko committed
1153

Alan Mishchenko committed
1154 1155 1156
  Description [J. Rajski and J. Vasudevamurthi, "The testability-
  preserving concurrent decomposition and factorization of Boolean
  expressions", IEEE TCAD, Vol. 11, No. 6, June 1992, pp. 778-793.]
Alan Mishchenko committed
1157 1158 1159 1160 1161 1162
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
1163
int Fx_FastExtract( Vec_Wec_t * vCubes, int ObjIdMax, int nNewNodesMax, int LitCountMax, int fCanonDivs, int fVerbose, int fVeryVerbose )
Alan Mishchenko committed
1164
{
1165
    int fVeryVeryVerbose = 0;
1166
    int i, iDiv, fWarning = 0;
Alan Mishchenko committed
1167
    Fx_Man_t * p;
1168
    abctime clk = Abc_Clock();
Alan Mishchenko committed
1169 1170
    // initialize the data-structure
    p = Fx_ManStart( vCubes );
1171
    p->LitCountMax = LitCountMax;
1172
    p->fCanonDivs = fCanonDivs;
Alan Mishchenko committed
1173
    Fx_ManCreateLiterals( p, ObjIdMax );
1174
    Fx_ManComputeLevel( p );
Alan Mishchenko committed
1175 1176
    Fx_ManCreateDivisors( p );
    if ( fVeryVerbose )
1177
        Fx_PrintDivisors( p );
Alan Mishchenko committed
1178
    if ( fVerbose )
1179
        Fx_PrintStats( p, Abc_Clock() - clk );
Alan Mishchenko committed
1180
    // perform extraction
1181
    p->timeStart = Abc_Clock();
1182
    for ( i = 0; i < nNewNodesMax && Vec_QueTopPriority(p->vPrio) > 0.0; i++ )
Alan Mishchenko committed
1183
    {
1184
        iDiv = Vec_QuePop(p->vPrio);
1185
        if ( fVeryVerbose )
Alan Mishchenko committed
1186
            Fx_PrintDiv( p, iDiv );
1187
        Fx_ManUpdate( p, iDiv, &fWarning );
1188
        if ( fVeryVeryVerbose )
1189
            Fx_PrintDivisors( p );
Alan Mishchenko committed
1190
    }
1191 1192
    if ( fVerbose )
        Fx_PrintStats( p, Abc_Clock() - clk );
Alan Mishchenko committed
1193
    Fx_ManStop( p );
Alan Mishchenko committed
1194 1195
    // return the result
    Vec_WecRemoveEmpty( vCubes );
Alan Mishchenko committed
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
    return 1;
}



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


ABC_NAMESPACE_IMPL_END