abcRec3.c 50.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/**CFile****************************************************************

  FileName    [abcRec2.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Network and node package.]

  Synopsis    [Record of semi-canonical AIG subgraphs.]

  Author      [Allan Yang, Alan Mishchenko]
  
  Affiliation [Fudan University in Shanghai, UC Berkeley]

  Date        [Ver. 1.0. Started - June 20, 2005.]

  Revision    [$Id: abcRec.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]

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

#include "base/abc/abc.h"
#include "map/if/if.h"
#include "bool/kit/kit.h"
#include "aig/gia/giaAig.h"
#include "misc/vec/vecMem.h"
26
#include "opt/dau/dau.h"
27
#include "misc/util/utilTruth.h"
28 29 30

ABC_NAMESPACE_IMPL_START

31 32
#define LMS_VAR_MAX    16  // LMS_VAR_MAX >= 6
#define LMS_MAX_WORD  (1<<(LMS_VAR_MAX-6))
33 34
//#define LMS_USE_OLD_FORM

35 36 37 38
////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

39 40
/*
    This LMS manager can be used in two modes:
41 42 43 44 45
        - library constuction
        - AIG level minimization
    To switch from library construction to AIG level minimization
    LSM manager should be restarted by dumping GIA (rec_dump3 <file>.aig) 
    and starting LMS manager again (rec_start3 <file>.aig).
46 47
*/

48 49 50 51 52 53 54 55
typedef struct Lms_Man_t_ Lms_Man_t;
struct Lms_Man_t_
{
    // parameters
    int               nVars;        // the number of variables
    int               nWords;       // the number of TT words
    int               nCuts;        // the max number of cuts to use
    int               fFuncOnly;    // record only functions
56 57
    int               fLibConstr;   // this manager is used for library construction
    // internal data for library construction
58
    Gia_Man_t *       pGia;         // the record
59
    Vec_Mem_t *       vTtMem;       // truth table memory and hash table
60
//    Vec_Mem_t *       vTtMem2;      // truth table memory and hash table
61 62 63 64 65 66
    Vec_Int_t *       vTruthIds;    // truth table IDs of each PO
    // internal data for AIG level minimization (allocated the first time it is called)
    Vec_Int_t *       vTruthPo;     // first PO where this canonicized truth table was seen
    Vec_Wrd_t *       vDelays;      // pin-to-pin delays of each PO
    Vec_Str_t *       vAreas;       // number of AND gates in each PO
    Vec_Int_t *       vFreqs;       // subgraph usage frequencies
67
    Vec_Int_t *       vTruthFreqs;  // truth table usage frequencies
68 69
    // temporaries
    Vec_Ptr_t *       vNodes;       // the temporary nodes
70
    Vec_Ptr_t *       vLabelsP;     // temporary storage for HOP node labels
71
    Vec_Int_t *       vLabels;      // temporary storage for AIG node labels
72
    Vec_Str_t *       vSupps;       // used temporarily by TT dumping
73 74
    word              pTemp1[LMS_MAX_WORD]; // copy of the truth table
    word              pTemp2[LMS_MAX_WORD]; // copy of the truth table
75 76 77 78 79 80 81 82 83 84
    // statistics 
    int               nTried;
    int               nFilterSize;
    int               nFilterRedund;
    int               nFilterVolume;
    int               nFilterTruth;
    int               nFilterError;
    int               nFilterSame;
    int               nAdded;
    int               nAddedFuncs;
85
    int               nHoleInTheWall;
86
    // runtime
87 88 89 90 91 92 93
    abctime           timeTruth;
    abctime           timeCanon;
    abctime           timeBuild;
    abctime           timeCheck;
    abctime           timeInsert;
    abctime           timeOther;
    abctime           timeTotal;
94 95
};

96
static Lms_Man_t * s_pMan3 = NULL;
97 98 99 100 101 102 103

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

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

104 105 106 107 108 109 110 111 112
  Synopsis    [Compute delay/area profiles of POs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
113 114 115
static inline int  Lms_DelayGet( word D, int v )           { assert(v >= 0 && v < LMS_VAR_MAX); return (int)((D >> (v << 2)) & 0xF);                             }
static inline void Lms_DelaySet( word * pD, int v, int d ) { assert(v >= 0 && v < LMS_VAR_MAX); assert(d >= 0 && d < LMS_VAR_MAX); *pD |= ((word)d << (v << 2)); }
static inline word Lms_DelayInit( int v )                  { assert(v >= 0 && v < LMS_VAR_MAX); return (word)1 << (v << 2);                                      }
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
static inline word Lms_DelayMax( word D1, word D2, int nVars )
{
    int v, Max;
    word D = 0;
    for ( v = 0; v < nVars; v++ )
        if ( (Max = Abc_MaxInt(Lms_DelayGet(D1, v), Lms_DelayGet(D2, v))) )
            Lms_DelaySet( &D, v, Abc_MinInt(Max + 1, 15) );
    return D;
}
static inline word Lms_DelayDecrement( word D1, int nVars )
{
    int v;
    word D = 0;
    for ( v = 0; v < nVars; v++ )
        if ( Lms_DelayGet(D1, v) )
            Lms_DelaySet( &D, v, Lms_DelayGet(D1, v) - 1 );
    return D;
}
static inline int Lms_DelayEqual( word D1, word D2, int nVars ) // returns 1 if D1 has the same delays than D2
{
    int v;
    for ( v = 0; v < nVars; v++ )
        if ( Lms_DelayGet(D1, v) != Lms_DelayGet(D2, v) )
            return 0;
    return 1;
}
static inline int Lms_DelayDom( word D1, word D2, int nVars ) // returns 1 if D1 has the same or smaller delays than D2
{
    int v;
    for ( v = 0; v < nVars; v++ )
        if ( Lms_DelayGet(D1, v) > Lms_DelayGet(D2, v) )
            return 0;
    return 1;
}
static inline void Lms_DelayPrint( word D, int nVars )
{
    int v;
    printf( "Delay profile = {" );
    for ( v = 0; v < nVars; v++ )
        printf( " %d", Lms_DelayGet(D, v) );
    printf( " }\n" );
}
Vec_Wrd_t * Lms_GiaDelays( Gia_Man_t * p )
159
{
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 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 201 202 203 204 205 206 207 208 209 210 211 212 213 214
    Vec_Wrd_t * vDelays, * vResult;
    Gia_Obj_t * pObj;
    int i;
    // compute delay profiles of all objects
    vDelays = Vec_WrdAlloc( Gia_ManObjNum(p) );
    Vec_WrdPush( vDelays, 0 ); // const 0
    Gia_ManForEachObj1( p, pObj, i )
    {
        if ( Gia_ObjIsAnd(pObj) )
            Vec_WrdPush( vDelays, Lms_DelayMax( Vec_WrdEntry(vDelays, Gia_ObjFaninId0(pObj, i)), Vec_WrdEntry(vDelays, Gia_ObjFaninId1(pObj, i)), Gia_ManCiNum(p) ) );
        else if ( Gia_ObjIsCo(pObj) )
            Vec_WrdPush( vDelays, Lms_DelayDecrement( Vec_WrdEntry(vDelays, Gia_ObjFaninId0(pObj, i)), Gia_ManCiNum(p) ) );
        else if ( Gia_ObjIsCi(pObj) )
            Vec_WrdPush( vDelays, Lms_DelayInit( Gia_ObjCioId(pObj) ) );
        else assert( 0 );
    }
    // collect delay profiles of COs only
    vResult = Vec_WrdAlloc( Gia_ManCoNum(p) );
    Gia_ManForEachCo( p, pObj, i )
        Vec_WrdPush( vResult, Vec_WrdEntry(vDelays, Gia_ObjId(p, pObj)) );
    Vec_WrdFree( vDelays );
    return vResult;
}
void Lms_ObjAreaMark_rec( Gia_Obj_t * pObj )
{
    if ( pObj->fMark0 || Gia_ObjIsCi(pObj) )
        return;
    pObj->fMark0 = 1;
    Lms_ObjAreaMark_rec( Gia_ObjFanin0(pObj) );
    Lms_ObjAreaMark_rec( Gia_ObjFanin1(pObj) );
}
int  Lms_ObjAreaUnmark_rec( Gia_Obj_t * pObj )
{
    if ( !pObj->fMark0 || Gia_ObjIsCi(pObj) )
        return 0;
    pObj->fMark0 = 0;
    return 1 + Lms_ObjAreaUnmark_rec( Gia_ObjFanin0(pObj) ) 
             + Lms_ObjAreaUnmark_rec( Gia_ObjFanin1(pObj) );
}
int Lms_ObjArea( Gia_Obj_t * pObj )
{
    assert( Gia_ObjIsAnd(pObj) );
    Lms_ObjAreaMark_rec( pObj );
    return Lms_ObjAreaUnmark_rec( pObj );    
}
Vec_Str_t * Lms_GiaAreas( Gia_Man_t * p )
{
    Vec_Str_t * vAreas;
    Gia_Obj_t * pObj;
    int i;
    vAreas = Vec_StrAlloc( Gia_ManCoNum(p) );
    Gia_ManForEachCo( p, pObj, i )
        Vec_StrPush( vAreas, (char)(Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) ? Lms_ObjArea(Gia_ObjFanin0(pObj)) : 0) );
    return vAreas;
}
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
Vec_Str_t * Lms_GiaSuppSizes( Gia_Man_t * p )
{
    Vec_Str_t * vResult;
    Vec_Str_t * vSupps;
    Gia_Obj_t * pObj;
    int i;
    vSupps = Vec_StrAlloc( Gia_ManObjNum(p) );
    Vec_StrPush( vSupps, 0 );
    Gia_ManForEachObj1( p, pObj, i )
    {
        if ( Gia_ObjIsAnd(pObj) )
            Vec_StrPush( vSupps, (char)Abc_MaxInt( Vec_StrEntry(vSupps, Gia_ObjFaninId0(pObj, i)), Vec_StrEntry(vSupps, Gia_ObjFaninId1(pObj, i)) ) );
        else if ( Gia_ObjIsCo(pObj) )
            Vec_StrPush( vSupps, Vec_StrEntry(vSupps, Gia_ObjFaninId0(pObj, i)) );
        else if ( Gia_ObjIsCi(pObj) )
            Vec_StrPush( vSupps, (char)(Gia_ObjCioId(pObj)+1) );
        else assert( 0 );
    }
    assert( Vec_StrSize(vSupps) == Gia_ManObjNum(p) );
    vResult = Vec_StrAlloc( Gia_ManCoNum(p) );
    Gia_ManForEachCo( p, pObj, i )
        Vec_StrPush( vResult, Vec_StrEntry(vSupps, Gia_ObjId(p, pObj)) );
    Vec_StrFree( vSupps );
    return vResult;
}
void Lms_GiaProfilesPrint( Gia_Man_t * p )
{
    Gia_Obj_t * pObj;
    int i;
    Vec_Wrd_t * vDelays;
    Vec_Str_t * vAreas;
    vDelays = Lms_GiaDelays( p );
    vAreas = Lms_GiaAreas( p );
    Gia_ManForEachPo( p, pObj, i )
    {
        printf( "%6d : ", i );
        printf( "A = %2d  ", Vec_StrEntry(vAreas, i) );
        Lms_DelayPrint( Vec_WrdEntry(vDelays, i), Gia_ManPiNum(p) );
//        Lms_GiaPrintSubgraph( p, pObj );
//        printf( "\n" );
    }
    Vec_WrdFree( vDelays );
    Vec_StrFree( vAreas );
}
259

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
/**Function*************************************************************

  Synopsis    [Prints one GIA subgraph.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Lms_GiaPrintSubgraph_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
{
    if ( !pObj->fMark0 || Gia_ObjIsCi(pObj) )
        return;
    pObj->fMark0 = 0;
    assert( Gia_ObjIsAnd(pObj) );
    Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin0(pObj) );
    Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin1(pObj) );
    Gia_ObjPrint( p, pObj );
280
}
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
void Lms_GiaPrintSubgraph( Gia_Man_t * p, Gia_Obj_t * pObj )
{
    assert( Gia_ObjIsCo(pObj) );
    if ( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) )
    {
        Lms_ObjAreaMark_rec( Gia_ObjFanin0(pObj) );
        Lms_GiaPrintSubgraph_rec( p, Gia_ObjFanin0(pObj) ); 
    }
    else
        Gia_ObjPrint( p, Gia_ObjFanin0(pObj) );
    Gia_ObjPrint( p, pObj );
}

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

296
  Synopsis    []
297 298 299 300 301 302 303 304

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
305
Lms_Man_t * Lms_ManStart( Gia_Man_t * pGia, int nVars, int nCuts, int fFuncOnly, int fVerbose )
306
{
307
    Lms_Man_t * p;
308
    abctime clk, clk2 = Abc_Clock();
309 310 311 312 313 314 315 316 317 318 319 320
    // if GIA is given, use the number of variables from GIA
    nVars = pGia ? Gia_ManCiNum(pGia) : nVars;
    assert( nVars >= 6 && nVars <= LMS_VAR_MAX );
    // allocate manager
    p = ABC_CALLOC( Lms_Man_t, 1 );
    // parameters
    p->nVars = nVars;
    p->nCuts = nCuts;
    p->nWords = Abc_Truth6WordNum( nVars );
    p->fFuncOnly = fFuncOnly;
    // internal data for library construction
    p->vTtMem = Vec_MemAlloc( p->nWords, 12 ); // 32 KB/page for 6-var functions
321
//    p->vTtMem2 = Vec_MemAlloc( p->nWords, 12 ); // 32 KB/page for 6-var functions
322
    Vec_MemHashAlloc( p->vTtMem, 10000 );
323
//    Vec_MemHashAlloc( p->vTtMem2, 10000 );
324 325 326 327
    if ( fFuncOnly )
        return p;    
    p->vTruthIds = Vec_IntAlloc( 10000 );
    if ( pGia == NULL )
328
    {
329 330 331 332 333
        int i;
        p->pGia = Gia_ManStart( 10000 );
        p->pGia->pName = Abc_UtilStrsav( "record" );
        for ( i = 0; i < nVars; i++ )
            Gia_ManAppendCi( p->pGia );
334
    }
335 336 337 338 339 340 341 342 343 344
    else
    {
        Gia_Obj_t * pObj;
        word * pTruth;
        int i, Index, Prev = -1;
        p->pGia = pGia;
        // populate the manager with subgraphs present in GIA
        p->nAdded = Gia_ManCoNum( p->pGia );
        Gia_ManForEachCo( p->pGia, pObj, i )
        {
345
            clk = Abc_Clock();
346
            pTruth = Gia_ObjComputeTruthTable( p->pGia, pObj );
347 348
            p->timeTruth += Abc_Clock() - clk;
            clk = Abc_Clock();
349
            Index = Vec_MemHashInsert( p->vTtMem, pTruth );
350
            p->timeInsert += Abc_Clock() - clk;
351 352 353 354 355 356 357 358 359
            assert( Index == Prev || Index == Prev + 1 ); // GIA subgraphs should be ordered
            Vec_IntPush( p->vTruthIds, Index );
            Prev = Index;
        }
    }
    // temporaries
    p->vNodes    = Vec_PtrAlloc( 1000 );
    p->vLabelsP  = Vec_PtrAlloc( 1000 );
    p->vLabels   = Vec_IntAlloc( 1000 );
360
p->timeTotal += Abc_Clock() - clk2;
361
    return p;    
362
}
363 364 365 366 367 368 369 370 371 372 373
void Lms_ManStop( Lms_Man_t * p )
{
    // temporaries
    Vec_IntFreeP( &p->vLabels );
    Vec_PtrFreeP( &p->vLabelsP );
    Vec_PtrFreeP( &p->vNodes );
    // internal data for AIG level minimization
    Vec_IntFreeP( &p->vTruthPo );
    Vec_WrdFreeP( &p->vDelays );
    Vec_StrFreeP( &p->vAreas );
    Vec_IntFreeP( &p->vFreqs );
374
    Vec_IntFreeP( &p->vTruthFreqs );
375 376 377
    // internal data for library construction
    Vec_IntFreeP( &p->vTruthIds );
    Vec_MemHashFree( p->vTtMem );
378
//    Vec_MemHashFree( p->vTtMem2 );
379
    Vec_MemFree( p->vTtMem );
380
//    Vec_MemFree( p->vTtMem2 );
381
    Gia_ManStopP( &p->pGia );
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    ABC_FREE( p );
}
void Lms_ManPrepare( Lms_Man_t * p )
{
    // compute the first PO for each semi-canonical form
    int i, Entry;
    assert( !p->fLibConstr );
    assert( p->vTruthPo == NULL );
    p->vTruthPo = Vec_IntStartFull( Vec_MemEntryNum(p->vTtMem)+1 );
    assert( Vec_IntFindMin(p->vTruthIds) >= 0 );
    assert( Vec_IntFindMax(p->vTruthIds) < Vec_MemEntryNum(p->vTtMem) );
    Vec_IntForEachEntry( p->vTruthIds, Entry, i )
        if ( Vec_IntEntry(p->vTruthPo, Entry) == -1 )
            Vec_IntWriteEntry( p->vTruthPo, Entry, i );
    Vec_IntWriteEntry( p->vTruthPo, Vec_MemEntryNum(p->vTtMem), Gia_ManCoNum(p->pGia) );
    // compute delay/area and init frequency
    assert( p->vDelays == NULL );
    assert( p->vAreas == NULL );
    assert( p->vFreqs == NULL );
    p->vDelays = Lms_GiaDelays( p->pGia );
    p->vAreas  = Lms_GiaAreas( p->pGia );
    p->vFreqs  = Vec_IntStart( Gia_ManCoNum(p->pGia) );
}
void Lms_ManPrintFuncStats( Lms_Man_t * p )
406 407
{
    Vec_Str_t * vSupps;
408 409 410 411 412 413 414 415 416 417
    int Counters[LMS_VAR_MAX+1] = {0}, CountersS[LMS_VAR_MAX+1] = {0};
    int i, Entry, Next;
    if ( p->pGia == NULL )
        return;
    if ( p->fLibConstr )
        return;
    if ( p->vTruthPo == NULL )
        Lms_ManPrepare( p );
    vSupps = Lms_GiaSuppSizes( p->pGia );
    Vec_IntForEachEntry( p->vTruthPo, Entry, i )
418
    {
419 420 421
        if ( i == Vec_IntSize(p->vTruthPo) - 1 )
            break;
        Next = Vec_IntEntry( p->vTruthPo, i+1 );
422 423
        Counters[(int)Vec_StrEntry(vSupps, Entry)]++;
        CountersS[(int)Vec_StrEntry(vSupps, Entry)] += Next - Entry;
424
    }
425 426 427
    for ( i = 0; i <= LMS_VAR_MAX; i++ )
        if ( Counters[i] )
            printf( "Inputs = %2d.  Funcs = %8d.  Subgrs = %8d.  Ratio = %6.2f.\n", i, Counters[i], CountersS[i], 1.0*CountersS[i]/Counters[i] );
428 429
    Vec_StrFree( vSupps );
}
430 431 432 433 434 435 436 437 438 439 440 441
void Lms_ManPrintFreqStats( Lms_Man_t * p )
{
    int CountDsdNpn[3]  = {0};  // full/part/none
    int CountDsdAll[3]  = {0};  // full/part/none
    int CountStepNpn[3] = {0};  // full/1step/complex
    int CountStepAll[3] = {0};  // full/1step/complex
    char pBuffer[1000];
    int nSuppSize;
    int nNonDecSize;
    word * pTruth;
    int i, Freq, Status;
    printf( "Cuts  = %10d. ",            p->nTried );
442
//    printf( "Funcs = %10d (%6.2f %%). ", Vec_MemEntryNum(p->vTtMem2), 100.0*Vec_MemEntryNum(p->vTtMem2)/p->nTried );
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
    printf( "Class = %10d (%6.2f %%). ", Vec_MemEntryNum(p->vTtMem),  100.0*Vec_MemEntryNum(p->vTtMem)/p->nTried );
    printf( "\n" );
//    return;

    Vec_IntForEachEntry( p->vTruthFreqs, Freq, i )
    {
        pTruth = Vec_MemReadEntry(p->vTtMem, i);
/*
        printf( "%6d -- %6d : ", i, Freq );
        Kit_DsdWriteFromTruth( pBuffer, (unsigned *)pTruth, p->nVars );
        printf( "%s\n", pBuffer );
*/
        nSuppSize = Abc_TtSupportSize( pTruth, p->nVars );
        nNonDecSize = Dau_DsdDecompose( pTruth, p->nVars, 0, 0, pBuffer );
        if ( nNonDecSize == 0 )
        {
            CountDsdNpn[0]++;
            CountDsdAll[0] += Freq;
        }
        else if ( nNonDecSize < nSuppSize )
        {
            CountDsdNpn[1]++;
            CountDsdAll[1] += Freq;
        }
        else // non-dec
        {
            CountDsdNpn[2]++;
            CountDsdAll[2] += Freq;
        }

        if ( nNonDecSize == 0 )
        {
            CountStepNpn[0]++;
            CountStepAll[0] += Freq;
            continue;
        }

        // check the non dec core
481
        Status = Dau_DsdCheck1Step( NULL, pTruth, nNonDecSize, NULL );
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
        if ( Status >= 0 )
        {
            CountStepNpn[1]++;
            CountStepAll[1] += Freq;
        }
        else
        {
            assert( Status == -2 );
            CountStepNpn[2]++;
            CountStepAll[2] += Freq;
        }
    }

    // print the results
    printf( "NPN: " );
    printf( "Full = %6.2f %%  ", 100.0 * CountDsdNpn[0] / Vec_MemEntryNum(p->vTtMem) );
    printf( "Part = %6.2f %%  ", 100.0 * CountDsdNpn[1] / Vec_MemEntryNum(p->vTtMem) );
    printf( "None = %6.2f %%  ", 100.0 * CountDsdNpn[2] / Vec_MemEntryNum(p->vTtMem) );
//    printf( "\n" );
    printf( "   " );
    // print the results
    printf( "All: " );
    printf( "Full = %6.2f %%  ", 100.0 * CountDsdAll[0] / p->nTried );
    printf( "Part = %6.2f %%  ", 100.0 * CountDsdAll[1] / p->nTried );
    printf( "None = %6.2f %%  ", 100.0 * CountDsdAll[2] / p->nTried );
    printf( "\n" );

    // print the results
    printf( "NPN: " );
    printf( "Full = %6.2f %%  ", 100.0 * CountStepNpn[0] / Vec_MemEntryNum(p->vTtMem) );
    printf( "1stp = %6.2f %%  ", 100.0 * CountStepNpn[1] / Vec_MemEntryNum(p->vTtMem) );
    printf( "Comp = %6.2f %%  ", 100.0 * CountStepNpn[2] / Vec_MemEntryNum(p->vTtMem) );
//    printf( "\n" );
    printf( "   " );
    // print the results
    printf( "All: " );
    printf( "Full = %6.2f %%  ", 100.0 * CountStepAll[0] / p->nTried );
    printf( "1stp = %6.2f %%  ", 100.0 * CountStepAll[1] / p->nTried );
    printf( "Comp = %6.2f %%  ", 100.0 * CountStepAll[2] / p->nTried );
    printf( "\n" );

}
524 525 526 527 528 529
void Lms_ManPrint( Lms_Man_t * p )
{
//    Gia_ManPrintStats( p->pGia, 0, 0 );
    printf( "Library with %d vars has %d classes and %d AIG subgraphs with %d AND nodes.\n", 
        p->nVars, Vec_MemEntryNum(p->vTtMem), p->nAdded, p->pGia ? Gia_ManAndNum(p->pGia) : 0 );

530
//    Lms_ManPrintFreqStats( p );
531
    Lms_ManPrintFuncStats( p );
532

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    p->nAddedFuncs = Vec_MemEntryNum(p->vTtMem);
    printf( "Subgraphs tried                             = %10d. (%6.2f %%)\n", p->nTried,         !p->nTried? 0 : 100.0*p->nTried/p->nTried );
    printf( "Subgraphs filtered by support size          = %10d. (%6.2f %%)\n", p->nFilterSize,    !p->nTried? 0 : 100.0*p->nFilterSize/p->nTried );
    printf( "Subgraphs filtered by structural redundancy = %10d. (%6.2f %%)\n", p->nFilterRedund,  !p->nTried? 0 : 100.0*p->nFilterRedund/p->nTried );
    printf( "Subgraphs filtered by volume                = %10d. (%6.2f %%)\n", p->nFilterVolume,  !p->nTried? 0 : 100.0*p->nFilterVolume/p->nTried );
    printf( "Subgraphs filtered by TT redundancy         = %10d. (%6.2f %%)\n", p->nFilterTruth,   !p->nTried? 0 : 100.0*p->nFilterTruth/p->nTried );
    printf( "Subgraphs filtered by error                 = %10d. (%6.2f %%)\n", p->nFilterError,   !p->nTried? 0 : 100.0*p->nFilterError/p->nTried );
    printf( "Subgraphs filtered by isomorphism           = %10d. (%6.2f %%)\n", p->nFilterSame,    !p->nTried? 0 : 100.0*p->nFilterSame/p->nTried );
    printf( "Subgraphs added                             = %10d. (%6.2f %%)\n", p->nAdded,         !p->nTried? 0 : 100.0*p->nAdded/p->nTried );
    printf( "Functions added                             = %10d. (%6.2f %%)\n", p->nAddedFuncs,    !p->nTried? 0 : 100.0*p->nAddedFuncs/p->nTried );
    if ( p->nHoleInTheWall )
    printf( "Cuts whose logic structure has a hole       = %10d. (%6.2f %%)\n", p->nHoleInTheWall, !p->nTried? 0 : 100.0*p->nHoleInTheWall/p->nTried );

    p->timeOther = p->timeTotal - p->timeTruth - p->timeCanon - p->timeBuild - p->timeCheck - p->timeInsert;
    ABC_PRTP( "Runtime: Truth ", p->timeTruth,  p->timeTotal );
    ABC_PRTP( "Runtime: Canon ", p->timeCanon,  p->timeTotal );
    ABC_PRTP( "Runtime: Build ", p->timeBuild,  p->timeTotal );
    ABC_PRTP( "Runtime: Check ", p->timeCheck,  p->timeTotal );
    ABC_PRTP( "Runtime: Insert", p->timeInsert, p->timeTotal );
    ABC_PRTP( "Runtime: Other ", p->timeOther,  p->timeTotal );
    ABC_PRTP( "Runtime: TOTAL ", p->timeTotal,  p->timeTotal );
}
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

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

  Synopsis    [Recanonicizes the library and add it to the current library.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkRecLibMerge3( Gia_Man_t * pLib )
{
    int fCheck = 0;
    Lms_Man_t * p = s_pMan3;
    Gia_Man_t * pGia = p->pGia;
    Vec_Str_t * vSupps;
573
    char pCanonPerm[LMS_VAR_MAX];
574
    unsigned uCanonPhase;
575
    word * pTruth;
576
    int i, k, Index, iFanin0, iFanin1, nLeaves;
577
    Gia_Obj_t * pObjPo, * pDriver, * pTemp = NULL;
578
    abctime clk, clk2 = Abc_Clock();
579

580 581 582 583 584
    if ( Gia_ManCiNum(pLib) != Gia_ManCiNum(pGia) )
    {
        printf( "The number of Library inputs (%d) differs from the number of Gia inputs (%d).\n", Gia_ManCiNum(pLib), Gia_ManCiNum(pGia) );
        return;
    }
585 586 587
    assert( Gia_ManCiNum(pLib) == Gia_ManCiNum(pGia) );

    // create hash table if not available
588
    if ( Vec_IntSize(&pGia->vHTable) == 0 )
589 590 591
        Gia_ManHashStart( pGia );

    // add AIG subgraphs
592
    vSupps = Lms_GiaSuppSizes( pLib );
593 594 595 596 597
    Gia_ManForEachCo( pLib, pObjPo, k )
    {
        // get support size
        nLeaves = Vec_StrEntry(vSupps, k);
        assert( nLeaves > 1 );
598

599
        // compute the truth table
600
clk = Abc_Clock();
601
        pTruth = Gia_ObjComputeTruthTable( pLib, Gia_ObjFanin0(pObjPo) );
602
p->timeTruth += Abc_Clock() - clk;
603
        // semi-canonicize
604
clk = Abc_Clock();
605
        memcpy( p->pTemp1, pTruth, p->nWords * sizeof(word) );
606
#ifdef LMS_USE_OLD_FORM
607
        uCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm );
608 609 610
#else
        uCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm );
#endif
611
        Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars );
612
p->timeCanon += Abc_Clock() - clk;
613
        // pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth
614 615
        if ( nLeaves == 2 && Abc_TtSupportSize(pTruth, 2) != 2 )
            continue;
616

617
clk = Abc_Clock();
618 619 620 621 622 623 624 625 626 627 628
        // map cut leaves into elementary variables of GIA
        for ( i = 0; i < nLeaves; i++ )
            Gia_ManCi( pLib, pCanonPerm[i] )->Value = Abc_Var2Lit( Gia_ObjId(pGia, Gia_ManPi(pGia, i)), (uCanonPhase >> i) & 1 );
        // build internal nodes
        assert( Vec_IntSize(pLib->vTtNodes) > 0 );
        Gia_ManForEachObjVec( pLib->vTtNodes, pLib, pTemp, i )
        {
            iFanin0 = Abc_LitNotCond( Gia_ObjFanin0(pTemp)->Value, Gia_ObjFaninC0(pTemp) );
            iFanin1 = Abc_LitNotCond( Gia_ObjFanin1(pTemp)->Value, Gia_ObjFaninC1(pTemp) );
            pTemp->Value = Gia_ManHashAnd( pGia, iFanin0, iFanin1 );
        }
629
p->timeBuild += Abc_Clock() - clk;
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645

        // check if this node is already driving a PO
        assert( Gia_ObjIsAnd(pTemp) );
        pDriver = Gia_ManObj(pGia, Abc_Lit2Var(pTemp->Value));
        if ( pDriver->fMark1 )
        {
            p->nFilterSame++;
            continue;
        }
        pDriver->fMark1 = 1;
        // create output
        Gia_ManAppendCo( pGia, Abc_LitNotCond( pTemp->Value, (uCanonPhase >> nLeaves) & 1 ) );

        // verify truth table
        if ( fCheck )
        {
646
clk = Abc_Clock();
647 648
        pTemp = Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1);
        pTruth = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1) );
649
p->timeCheck += Abc_Clock() - clk;
650 651 652
        if ( memcmp( p->pTemp1, pTruth, p->nWords * sizeof(word) ) != 0 )
        {
    
653
            Kit_DsdPrintFromTruth( (unsigned *)pTruth, nLeaves ); printf( "\n" );
654 655 656 657 658 659 660 661 662 663 664 665
            Kit_DsdPrintFromTruth( (unsigned *)p->pTemp1, nLeaves ); printf( "\n" );
            printf( "Truth table verification has failed.\n" );
    
            // drive PO with constant
            Gia_ManPatchCoDriver( pGia, Gia_ManCoNum(pGia)-1, 0 );
            // save truth table ID
            Vec_IntPush( p->vTruthIds, -1 );
            p->nFilterTruth++;
            continue;
        }
        }

666
clk = Abc_Clock();
667 668 669 670 671 672
        // add the resulting truth table to the hash table 
        Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 );
        // save truth table ID
        Vec_IntPush( p->vTruthIds, Index );
        assert( Gia_ManCoNum(pGia) == Vec_IntSize(p->vTruthIds) );
        p->nAdded++;
673
p->timeInsert += Abc_Clock() - clk;
674 675
    }
    Vec_StrFree( vSupps );
676
p->timeTotal += Abc_Clock() - clk2;
677 678
}

679 680 681

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

682
  Synopsis    [Evaluates one cut during library construction.]
683 684 685 686 687 688 689 690 691 692

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Abc_NtkRecAddCut3( If_Man_t * pIfMan, If_Obj_t * pRoot, If_Cut_t * pCut )
{
693
    Lms_Man_t * p = s_pMan3;
694
    char pCanonPerm[LMS_VAR_MAX];
695
    unsigned uCanonPhase;
696
    int i, Index, iFanin0, iFanin1, fHole;
697
    int nLeaves = If_CutLeaveNum(pCut);
698 699
    Vec_Ptr_t * vNodes = p->vNodes;
    Gia_Man_t * pGia = p->pGia;
700
    Gia_Obj_t * pDriver;
701
    If_Obj_t * pIfObj = NULL;
702
    word * pTruth;
703
    abctime clk;
704
    p->nTried++;
705 706

    // skip small cuts
707
    assert( p->nVars == (int)pCut->nLimit );
708
    if ( nLeaves < 2 || (nLeaves == 2 && Abc_TtSupportSize(If_CutTruthW(pIfMan, pCut), 2) != 2) )
709
    {
710
        p->nFilterSize++;
711 712 713
        return 1;
    }

714 715
//    if ( p->vTtMem2 )
//        Vec_MemHashInsert( p->vTtMem2, If_CutTruthW(pCut) );
716

717
    // semi-canonicize truth table
718
clk = Abc_Clock();
719
    memcpy( p->pTemp1, If_CutTruthW(pIfMan, pCut), p->nWords * sizeof(word) );
720
#ifdef LMS_USE_OLD_FORM
721
    uCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm );
722 723 724
#else
    uCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm );
#endif
725
    Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars );
726
p->timeCanon += Abc_Clock() - clk;
727 728
    // pCanonPerm and uCanonPhase show what was the variable corresponding to each var in the current truth

729 730
    if ( p->pGia == NULL )
    {
731
clk = Abc_Clock();
732
        // add the resulting truth table to the hash table 
733
        Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 );
734
/*
735 736 737 738 739 740 741
        if ( p->vTruthFreqs == NULL )
            p->vTruthFreqs = Vec_IntAlloc( 1000 );
        assert( Index <= Vec_IntSize(p->vTruthFreqs)  );
        if ( Index < Vec_IntSize(p->vTruthFreqs) )
            Vec_IntAddToEntry( p->vTruthFreqs, Index, 1 );
        else
            Vec_IntPush( p->vTruthFreqs, 1 );
742
*/
743
        p->nAdded++;
744
p->timeInsert += Abc_Clock() - clk;
745 746 747 748
        return 1;
    }

    // collect internal nodes and skip redundant cuts
749
clk = Abc_Clock();
750
    If_CutTraverse( pIfMan, pRoot, pCut, vNodes );
751
p->timeTruth += Abc_Clock() - clk;
752 753 754 755 756 757
    if ( Vec_PtrSize(vNodes) > 253 )
    {
        p->nFilterSize++;
        return 1;
    }

758
clk = Abc_Clock();
759 760
    // map cut leaves into elementary variables of GIA
    for ( i = 0; i < nLeaves; i++ )
761
        If_ManObj( pIfMan, pCut->pLeaves[(int)pCanonPerm[i]] )->iCopy = Abc_Var2Lit( Gia_ObjId(pGia, Gia_ManPi(pGia, i)), (uCanonPhase >> i) & 1 );
762
    // build internal nodes
763
    fHole = 0;
764 765 766 767 768 769
    assert( Vec_PtrSize(vNodes) > 0 );
    Vec_PtrForEachEntryStart( If_Obj_t *, vNodes, pIfObj, i, nLeaves )
    {
        if ( If_ObjIsCi(pIfObj) )
        {
            pIfObj->iCopy = 0;
770
            fHole = 1;
771 772 773 774 775 776
            continue;
        }
        iFanin0 = Abc_LitNotCond( If_ObjFanin0(pIfObj)->iCopy, If_ObjFaninC0(pIfObj) );
        iFanin1 = Abc_LitNotCond( If_ObjFanin1(pIfObj)->iCopy, If_ObjFaninC1(pIfObj) );
        pIfObj->iCopy = Gia_ManHashAnd( pGia, iFanin0, iFanin1 );
    }
777
    p->nHoleInTheWall += fHole;
778
p->timeBuild += Abc_Clock() - clk;
779 780

    // check if this node is already driving a PO
781
    assert( If_ObjIsAnd(pIfObj) );
782 783 784
    pDriver = Gia_ManObj(pGia, Abc_Lit2Var(pIfObj->iCopy));
    if ( pDriver->fMark1 )
    {
785
        p->nFilterSame++;
786 787
        return 1;
    }
788
    pDriver->fMark1 = 1;
789 790
    // create output
    Gia_ManAppendCo( pGia, Abc_LitNotCond( pIfObj->iCopy, (uCanonPhase >> nLeaves) & 1 ) );
791

792
    // verify truth table
793
clk = Abc_Clock();
794
    pTruth = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, Gia_ManCoNum(pGia)-1) );
795
p->timeCheck += Abc_Clock() - clk;
796
    if ( memcmp( p->pTemp1, pTruth, p->nWords * sizeof(word) ) != 0 )
797 798 799
    {
/*
        Kit_DsdPrintFromTruth( pTruth, nLeaves ); printf( "\n" );
800
        Kit_DsdPrintFromTruth( (unsigned *)p->pTemp1, nLeaves ); printf( "\n" );
801 802
        printf( "Truth table verification has failed.\n" );
*/
803 804 805 806 807
        // drive PO with constant
        Gia_ManPatchCoDriver( pGia, Gia_ManCoNum(pGia)-1, 0 );
        // save truth table ID
        Vec_IntPush( p->vTruthIds, -1 );
        p->nFilterTruth++;
808 809 810
        return 1;
    }

811
clk = Abc_Clock();
812 813 814 815 816 817
    // add the resulting truth table to the hash table 
    Index = Vec_MemHashInsert( p->vTtMem, p->pTemp1 );
    // save truth table ID
    Vec_IntPush( p->vTruthIds, Index );
    assert( Gia_ManCoNum(pGia) == Vec_IntSize(p->vTruthIds) );
    p->nAdded++;
818
p->timeInsert += Abc_Clock() - clk;
819 820 821 822 823
    return 1;
}

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

824
  Synopsis    [Top level procedure for library construction.]
825 826 827 828 829 830 831 832 833 834 835 836 837

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Abc_NtkRecAdd3( Abc_Ntk_t * pNtk, int fUseSOPB )
{
    extern Abc_Ntk_t * Abc_NtkIf( Abc_Ntk_t * pNtk, If_Par_t * pPars );
    If_Par_t Pars, * pPars = &Pars;
    Abc_Ntk_t * pNtkNew;
838
    int clk = Abc_Clock();
839 840
    if ( Abc_NtkGetChoiceNum( pNtk ) )
        printf( "Performing recoding structures with choices.\n" );
841 842
    // remember that the manager was used for library construction
    s_pMan3->fLibConstr = 1;
843
    // create hash table if not available
844
    if ( s_pMan3->pGia && Vec_IntSize(&s_pMan3->pGia->vHTable) == 0 )
845
        Gia_ManHashStart( s_pMan3->pGia );
846 847 848 849

    // set defaults
    memset( pPars, 0, sizeof(If_Par_t) );
    // user-controlable paramters
850 851
    pPars->nLutSize    =  s_pMan3->nVars;
    pPars->nCutsMax    =  s_pMan3->nCuts;
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
    pPars->DelayTarget = -1;
    pPars->Epsilon     =  (float)0.005;
    pPars->fArea       =  1;
    // internal parameters
    if ( fUseSOPB )
    {
        pPars->fTruth      =  1;
        pPars->fCutMin     =  0;
        pPars->fUsePerm    =  1; 
        pPars->fDelayOpt   =  1;
    }
    else
    {
        pPars->fTruth      =  1;
        pPars->fCutMin     =  1;
        pPars->fUsePerm    =  0; 
        pPars->fDelayOpt   =  0;
    }
    pPars->fSkipCutFilter = 0;
    pPars->pFuncCost   =  NULL;
    pPars->pFuncUser   =  Abc_NtkRecAddCut3;
    // perform recording
    pNtkNew = Abc_NtkIf( pNtk, pPars );
    Abc_NtkDelete( pNtkNew );
876
s_pMan3->timeTotal += Abc_Clock() - clk;
877 878 879 880 881 882 883 884 885 886 887 888 889
}

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

  Synopsis    [Returns min AIG level at the output fo the cut using the library.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
890
static inline int If_CutComputeDelay( If_Man_t * p, If_Cut_t * pCut, char * pCanonPerm, word DelayProfile )
891 892 893 894 895 896
{
    If_Obj_t* pLeaf;
    int nLeaves = If_CutLeaveNum(pCut);
    int i, delayTemp, delayMax = -ABC_INFINITY;
    for ( i = 0; i < nLeaves; i++ )
    {
897
        pLeaf     = If_ManObj(p, (pCut)->pLeaves[(int)pCanonPerm[i]]);
898
        delayTemp = If_ObjCutBest(pLeaf)->Delay + Lms_DelayGet(DelayProfile, i);
899
        delayMax  = Abc_MaxInt( delayMax, delayTemp );
900 901 902 903 904 905
    }
    return delayMax;
}
static inline int If_CutFindBestStruct( If_Man_t * pIfMan, If_Cut_t * pCut, char * pCanonPerm, unsigned * puCanonPhase, int * pBestPo )
{
    Lms_Man_t * p = s_pMan3;
906
    int i, * pTruthId, iFirstPo, iFirstPoNext, iBestPo;
907
    int BestDelay = ABC_INFINITY, BestArea = ABC_INFINITY, Delay, Area;
908
    int uSupport, nLeaves = If_CutLeaveNum( pCut );
909
    char * pPerm = If_CutPerm( pCut );
910
    word DelayProfile;
911
    abctime clk;
912 913
    pCut->fUser = 1;
    // compute support
914
    uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves );
915 916 917 918
    if ( uSupport == 0 )
    {
        pCut->Cost = 1;
        for ( i = 0; i < nLeaves; i++ )
919
            pPerm[i] = IF_BIG_CHAR;
920 921 922 923 924 925 926
        return 0;
    }
    if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 )
    {
        assert( Abc_TtSuppOnlyOne(uSupport) );
        pCut->Cost = 1;
        for ( i = 0; i < nLeaves; i++ )
927 928
            pPerm[i] = IF_BIG_CHAR;
        pPerm[Abc_TtSuppFindFirst(uSupport)] = 0;
929
        return If_ObjCutBest(If_ManObj(pIfMan, pCut->pLeaves[Abc_TtSuppFindFirst(uSupport)]))->Delay;
930 931
    }
    assert( Gia_WordCountOnes(uSupport) == nLeaves );
932 933

    // semicanonicize the function
934
clk = Abc_Clock();
935
    memcpy( p->pTemp1, If_CutTruthW(pIfMan, pCut), p->nWords * sizeof(word) );
936
#ifdef LMS_USE_OLD_FORM
937
    *puCanonPhase = Kit_TruthSemiCanonicize( (unsigned *)p->pTemp1, (unsigned *)p->pTemp2, nLeaves, pCanonPerm );
938 939 940
#else
    *puCanonPhase = Abc_TtCanonicize( p->pTemp1, nLeaves, pCanonPerm );
#endif
941
    Abc_TtStretch5( (unsigned *)p->pTemp1, nLeaves, p->nVars );
942
p->timeCanon += Abc_Clock() - clk;
943 944 945 946

    // get TT ID for the given class
    pTruthId = Vec_MemHashLookup( p->vTtMem, p->pTemp1 );
    if ( *pTruthId == -1 )
947 948
    {
        pCut->Cost = IF_COST_MAX;
949
        pCut->fUseless = 1;
950
        return ABC_INFINITY;
951
    }
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975

    // note that array p->vTruthPo contains the first PO for the given truth table
    // other POs belonging to the same equivalence class follow immediately after this one
    // to iterate through the POs, we need to perform the following steps

    // find the first PO of this class
    iFirstPo = Vec_IntEntry( p->vTruthPo, *pTruthId );
    // find the first PO of the next class
    iFirstPoNext = Vec_IntEntry( p->vTruthPo, *pTruthId+1 );
    // iterate through the subgraphs of this class
    iBestPo = -1;
    for ( i = iFirstPo; i < iFirstPoNext; i++ )
    {
        Delay = If_CutComputeDelay( pIfMan, pCut, pCanonPerm, Vec_WrdEntry(p->vDelays, i) );
        Area  = Vec_StrEntry(p->vAreas, i);
        if ( iBestPo == -1 || BestDelay > Delay || (BestDelay == Delay && BestArea > Area) )
        {
            iBestPo = i;
            BestDelay = Delay;
            BestArea = Area;
        }
    }
    if ( pBestPo )
        *pBestPo = iBestPo;
976 977

    // mark as user cut.
978
    DelayProfile = Vec_WrdEntry(p->vDelays, iBestPo);
979 980
    pCut->Cost = Vec_StrEntry(p->vAreas, iBestPo);
    for ( i = 0; i < nLeaves; i++ )
981
        pPerm[(int)pCanonPerm[i]] = Lms_DelayGet(DelayProfile, i);
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
    if ( 0 )
    {
        int Max = 0, Two = 0, pTimes[16];
        for ( i = 0; i < nLeaves; i++ )
            pTimes[i] = (int)If_ObjCutBest(If_CutLeaf(pIfMan, pCut, i))->Delay;
        for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
            Max = Abc_MaxInt( Max, pTimes[i] );
        for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
            if ( pTimes[i] != Max )
                Two = Abc_MaxInt( Two, pTimes[i] );
        if ( Two + 2 < Max && Max + 3 < BestDelay )
        {
            for ( i = 0; i < If_CutLeaveNum(pCut); i++ )
                printf( "%3d ", pTimes[i] );
            for ( ; i < pIfMan->pPars->nLutSize; i++ )
                printf( "    " );
            printf( "-> %3d   ", BestDelay );
            Dau_DsdPrintFromTruth( If_CutTruthW(pIfMan, pCut), If_CutLeaveNum(pCut) );
        }
    }
1002 1003 1004 1005 1006
    return BestDelay; 
}
int If_CutDelayRecCost3( If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pObj )
{
    Lms_Man_t * p = s_pMan3;
1007
    char pCanonPerm[LMS_VAR_MAX];
Alan Mishchenko committed
1008
    unsigned uCanonPhase = 0;
1009 1010 1011 1012 1013
    // make sure the cut functions match the library
    assert( p->nVars == (int)pCut->nLimit );
    // if this assertion fires, it means that LMS manager was used for library construction
    // in this case, GIA has to be written out and the manager restarted as described above
    assert( !p->fLibConstr );
1014 1015
    if ( p->vTruthPo == NULL )
        Lms_ManPrepare( p );
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
    // return the delay of the best structure
    return If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, NULL );
}

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

  Synopsis    [Reexpresses the best structure of the cut in the HOP manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Hop_Obj_t * Abc_RecToHop3( Hop_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, If_Obj_t * pIfObj )
{
    Lms_Man_t * p = s_pMan3;
1034
    char pCanonPerm[LMS_VAR_MAX];
Alan Mishchenko committed
1035
    unsigned uCanonPhase = 0;
1036 1037
    Hop_Obj_t * pFan0, * pFan1, * pHopObj;
    Gia_Man_t * pGia = p->pGia;
1038
    Gia_Obj_t * pGiaPo, * pGiaTemp = NULL;
1039
    int i, uSupport, BestPo = -1, nLeaves = If_CutLeaveNum(pCut);
1040 1041
    assert( pIfMan->pPars->fCutMin == 1 );

1042
    // compute support
1043
    uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves );
1044
    if ( uSupport == 0 )
1045
        return Hop_NotCond( Hop_ManConst0(pMan), If_CutTruthIsCompl(pCut) );
1046 1047 1048
    if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 )
    {
        assert( Abc_TtSuppOnlyOne(uSupport) );
1049
        return Hop_NotCond( Hop_IthVar(pMan, Abc_TtSuppFindFirst(uSupport)), If_CutTruthIsCompl(pCut) );
1050 1051 1052
    }
    assert( Gia_WordCountOnes(uSupport) == nLeaves );

1053 1054 1055 1056 1057 1058 1059
    // get the best output for this node
    If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, &BestPo );
    assert( BestPo >= 0 );
    pGiaPo = Gia_ManCo( pGia, BestPo );
    // collect internal nodes into pGia->vTtNodes
    if ( pGia->vTtNodes == NULL )
        pGia->vTtNodes = Vec_IntAlloc( 256 );
1060 1061 1062
    assert( Gia_ObjIsAnd( Gia_ObjFanin0(pGiaPo) ) );
    Gia_ObjCollectInternal( pGia, Gia_ObjFanin0(pGiaPo) );
    assert( Vec_IntSize(pGia->vTtNodes) > 0 );
1063

1064 1065 1066
    // collect HOP nodes for leaves
    Vec_PtrClear( p->vLabelsP );
    for ( i = 0; i < nLeaves; i++ )
1067 1068
        Vec_PtrPush( p->vLabelsP, Hop_NotCond(Hop_IthVar(pMan, pCanonPerm[i]), (uCanonPhase >> i) & 1) );

1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
    // compute HOP nodes for internal nodes
    Gia_ManForEachObjVec( pGia->vTtNodes, pGia, pGiaTemp, i )
    {
        pGiaTemp->fMark0 = 0; // unmark node marked by Gia_ObjCollectInternal()
        if ( Gia_ObjIsAnd(Gia_ObjFanin0(pGiaTemp)) )
            pFan0 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, Gia_ObjFanin0(pGiaTemp)) + nLeaves);
        else
            pFan0 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjCioId(Gia_ObjFanin0(pGiaTemp)));
        pFan0 = Hop_NotCond(pFan0, Gia_ObjFaninC0(pGiaTemp));
        if ( Gia_ObjIsAnd(Gia_ObjFanin1(pGiaTemp)) )
            pFan1 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, Gia_ObjFanin1(pGiaTemp)) + nLeaves);
        else
            pFan1 = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjCioId(Gia_ObjFanin1(pGiaTemp)));
        pFan1 = Hop_NotCond(pFan1, Gia_ObjFaninC1(pGiaTemp));

        pHopObj = Hop_And(pMan, pFan0, pFan1);
        Vec_PtrPush(p->vLabelsP, pHopObj);
    }
    // get the final result
    assert( Gia_ObjIsAnd(pGiaTemp) );
    pHopObj = (Hop_Obj_t *)Vec_PtrEntry(p->vLabelsP, Gia_ObjNum(pGia, pGiaTemp) + nLeaves);
    // complement the result if needed
1091
    return Hop_NotCond( pHopObj,  Gia_ObjFaninC0(pGiaPo) ^ ((uCanonPhase >> nLeaves) & 1) );    
1092 1093
}

1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
/**Function*************************************************************

  Synopsis    [Reexpresses the best structure of the cut in the GIA manager.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
1105
int Abc_RecToGia3( Gia_Man_t * pMan, If_Man_t * pIfMan, If_Cut_t * pCut, Vec_Int_t * vLeaves, int fHash )
1106 1107
{
    Lms_Man_t * p = s_pMan3;
1108
    char pCanonPerm[LMS_VAR_MAX];
1109
    unsigned uCanonPhase = 0;
1110 1111 1112 1113 1114 1115 1116 1117
    int iFan0, iFan1, iGiaObj;
    Gia_Man_t * pGia = p->pGia;
    Gia_Obj_t * pGiaPo, * pGiaTemp = NULL;
    int i, uSupport, BestPo = -1, nLeaves = If_CutLeaveNum(pCut);
    assert( pIfMan->pPars->fCutMin == 1 );
    assert( nLeaves == Vec_IntSize(vLeaves) );

    // compute support
1118
    uSupport = Abc_TtSupport( If_CutTruthW(pIfMan, pCut), nLeaves );
1119
    if ( uSupport == 0 )
1120
        return Abc_LitNotCond( 0, If_CutTruthIsCompl(pCut) );
1121 1122 1123
    if ( !Abc_TtSuppIsMinBase(uSupport) || uSupport == 1 )
    {
        assert( Abc_TtSuppOnlyOne(uSupport) );
1124
        return Abc_LitNotCond( Vec_IntEntry(vLeaves, Abc_TtSuppFindFirst(uSupport)), If_CutTruthIsCompl(pCut) );
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
    }
    assert( Gia_WordCountOnes(uSupport) == nLeaves );

    // get the best output for this node
    If_CutFindBestStruct( pIfMan, pCut, pCanonPerm, &uCanonPhase, &BestPo );
    assert( BestPo >= 0 );
    pGiaPo = Gia_ManCo( pGia, BestPo );

    // collect internal nodes into pGia->vTtNodes
    if ( pGia->vTtNodes == NULL )
        pGia->vTtNodes = Vec_IntAlloc( 256 );
    assert( Gia_ObjIsAnd( Gia_ObjFanin0(pGiaPo) ) );
    Gia_ObjCollectInternal( pGia, Gia_ObjFanin0(pGiaPo) );
    assert( Vec_IntSize(pGia->vTtNodes) > 0 );

    // collect GIA nodes for leaves
    Vec_IntClear( p->vLabels );
    for (i = 0; i < nLeaves; i++)
        Vec_IntPush( p->vLabels, Abc_LitNotCond(Vec_IntEntry(vLeaves, pCanonPerm[i]), (uCanonPhase >> i) & 1) );

    // compute HOP nodes for internal nodes
    Gia_ManForEachObjVec( pGia->vTtNodes, pGia, pGiaTemp, i )
    {
        pGiaTemp->fMark0 = 0; // unmark node marked by Gia_ObjCollectInternal()
        if ( Gia_ObjIsAnd(Gia_ObjFanin0(pGiaTemp)) )
            iFan0 = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, Gia_ObjFanin0(pGiaTemp)) + nLeaves);
        else
            iFan0 = Vec_IntEntry(p->vLabels, Gia_ObjCioId(Gia_ObjFanin0(pGiaTemp)));
        iFan0 = Abc_LitNotCond(iFan0, Gia_ObjFaninC0(pGiaTemp));
        if ( Gia_ObjIsAnd(Gia_ObjFanin1(pGiaTemp)) )
            iFan1 = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, Gia_ObjFanin1(pGiaTemp)) + nLeaves);
        else
            iFan1 = Vec_IntEntry(p->vLabels, Gia_ObjCioId(Gia_ObjFanin1(pGiaTemp)));
        iFan1 = Abc_LitNotCond(iFan1, Gia_ObjFaninC1(pGiaTemp));
        if ( fHash )
            iGiaObj = Gia_ManHashAnd(pMan, iFan0, iFan1);
        else
            iGiaObj = Gia_ManAppendAnd(pMan, iFan0, iFan1);
        Vec_IntPush(p->vLabels, iGiaObj);
    }
    // get the final result
    assert( Gia_ObjIsAnd(pGiaTemp) );
    iGiaObj = Vec_IntEntry(p->vLabels, Gia_ObjNum(pGia, pGiaTemp) + nLeaves);
    // complement the result if needed
1169
    return Abc_LitNotCond( iGiaObj,  Gia_ObjFaninC0(pGiaPo) ^ ((uCanonPhase >> nLeaves) & 1) ^ pCut->fCompl );    
1170 1171
}

1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198

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

  Synopsis    [Reduces GIA to contain only useful COs and internal nodes.]

  Description [During library construction, redundant nodes are added.
  Some COs are found to be useless because their TT does not match the
  (semi-canonicized TT) of the cut, etc.  This procedure reduces GIA
  to contains only useful (non-redundant, non-dominated) COs and the
  corresponding internal nodes. This procedure replaces GIA by a new GIA
  and creates new vTruthIds. The COs with the same truth table have
  adjacent IDs. This procedure does not change the truth tables.]
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
// count how many times TT occurs
Vec_Int_t * Lms_GiaCountTruths( Lms_Man_t * p )
{
    Vec_Int_t * vCounts = Vec_IntStart( Vec_MemEntryNum(p->vTtMem) );
    int i, Entry;
    Vec_IntForEachEntry( p->vTruthIds, Entry, i )
        if ( Entry >= 0 )
            Vec_IntAddToEntry( vCounts, Entry, 1 );
    return vCounts;
1199
}
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
// collect PO indexes worth visiting
Vec_Int_t * Lms_GiaCollectUsefulCos( Lms_Man_t * p )
{
    Vec_Int_t * vBegins = Vec_IntAlloc( Vec_MemEntryNum(p->vTtMem) );
    Vec_Int_t * vUseful = Vec_IntStartFull( Gia_ManCoNum(p->pGia) + Vec_MemEntryNum(p->vTtMem) );
    Vec_Int_t * vCounts = Lms_GiaCountTruths( p );
    int i, Entry, * pPlace, SumTotal = 0;
    // mark up the place for POs
    Vec_IntForEachEntry( vCounts, Entry, i )
    {
        assert( Entry > 0 );
        Vec_IntPush( vBegins, SumTotal );
        SumTotal += Entry + 1;
//        printf( "%d ", Entry );
    }
    Vec_IntPush( vBegins, SumTotal );
    // fill out POs in their places
    Vec_IntFill( vCounts, Vec_IntSize(vCounts), 0 );
    Vec_IntForEachEntry( p->vTruthIds, Entry, i )
    {
        if ( Entry < 0 )
            continue;
        pPlace = Vec_IntEntryP( vUseful, Vec_IntEntry(vBegins, Entry) + Vec_IntEntry(vCounts, Entry) );
        assert( *pPlace == -1 );
        *pPlace = i;
        Vec_IntAddToEntry( vCounts, Entry, 1 );
    }
    Vec_IntFree( vBegins );
    Vec_IntFree( vCounts );
    return vUseful;
}
// collect non-dominated COs
Vec_Int_t * Lms_GiaFindNonRedundantCos( Lms_Man_t * p )
{
    Vec_Int_t * vRemain;
    Vec_Int_t * vUseful;
    Vec_Wrd_t * vDelays;
    int i, k, EntryI, EntryK;
    word D1, D2;
    vDelays = Lms_GiaDelays( p->pGia );
    vUseful = Lms_GiaCollectUsefulCos( p );
    Vec_IntForEachEntry( vUseful, EntryI, i )
    {
        if ( EntryI < 0 )
            continue;
        D1 = Vec_WrdEntry(vDelays, EntryI);
        assert( D1 > 0 );
        Vec_IntForEachEntryStart( vUseful, EntryK, k, i+1 )
        {
            if ( EntryK == -1 )
                break;
            if ( EntryK == -2 )
                continue;
            D2 = Vec_WrdEntry(vDelays, EntryK);
            assert( D2 > 0 );
            if ( Lms_DelayDom(D1, D2, Gia_ManCiNum(p->pGia)) ) // D1 dominate D2
            {
                Vec_IntWriteEntry( vUseful, k, -2 );
                continue;
            }
            if ( Lms_DelayDom(D2, D1, Gia_ManCiNum(p->pGia)) ) // D2 dominate D1
            {
                Vec_IntWriteEntry( vUseful, i, -2 );
                break;
            }
        }
    }

    vRemain = Vec_IntAlloc( 1000 );
    Vec_IntForEachEntry( vUseful, EntryI, i )
        if ( EntryI >= 0 )
            Vec_IntPush( vRemain, EntryI );
    Vec_IntFree( vUseful );
    Vec_WrdFree( vDelays );
    return vRemain;
}
// replace GIA and vTruthIds by filtered ones
void Lms_GiaNormalize( Lms_Man_t * p )
{
    Gia_Man_t * pGiaNew;
    Gia_Obj_t * pObj;
    Vec_Int_t * vRemain;
    Vec_Int_t * vTruthIdsNew;
    int i, Entry, Prev = -1, Next;
    // collect non-redundant COs
    vRemain = Lms_GiaFindNonRedundantCos( p );
    // change these to be useful literals
    vTruthIdsNew = Vec_IntAlloc( Vec_IntSize(vRemain) );
    Vec_IntForEachEntry( vRemain, Entry, i )
    {
        pObj = Gia_ManCo(p->pGia, Entry);
        assert( Gia_ObjIsAnd(Gia_ObjFanin0(pObj)) );
        Vec_IntWriteEntry( vRemain, i, Gia_ObjFaninLit0p(p->pGia, pObj) );
        // create new truth IDs
        Next = Vec_IntEntry(p->vTruthIds, Gia_ObjCioId(pObj));
        assert( Prev <= Next );
        Vec_IntPush( vTruthIdsNew, Next );
        Prev = Next;
    }
    // create a new GIA
    Gia_ManForEachObj( p->pGia, pObj, i )
        assert( pObj->fMark0 == 0 );
    for ( i = 0; i < Gia_ManCoNum(p->pGia); i++ )
        Gia_ManPatchCoDriver( p->pGia, i, 0 );
    Vec_IntForEachEntry( vRemain, Entry, i )
        Gia_ManAppendCo( p->pGia, Entry );
//    pGiaNew = Gia_ManCleanup( p->pGia );
    pGiaNew = Gia_ManCleanupOutputs( p->pGia, Gia_ManCoNum(p->pGia) - Vec_IntSize(vRemain) );
    Gia_ManStop( p->pGia );
    p->pGia = pGiaNew;
    Vec_IntFree( vRemain );
    // update truth IDs
    Vec_IntFree( p->vTruthIds );
    p->vTruthIds = vTruthIdsNew;
//    Vec_IntPrint( vTruthIdsNew );
}

/**Function*************************************************************
1318

1319 1320 1321 1322 1323 1324 1325 1326 1327
  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
int Abc_NtkRecTruthCompare( int * p1, int * p2 ) 
{
    int Diff = Vec_StrEntry( s_pMan3->vSupps, *p1 ) - Vec_StrEntry( s_pMan3->vSupps, *p2 );
    if ( Diff )
        return Diff;
    return memcmp( Vec_MemReadEntry(s_pMan3->vTtMem, *p1), Vec_MemReadEntry(s_pMan3->vTtMem, *p2), sizeof(word) * s_pMan3->nWords ); 
}
void Abc_NtkRecDumpTt3( char * pFileName, int fBinary )
{
    FILE * pFile;
    char pBuffer[1000];
    Lms_Man_t * p = s_pMan3;
    Vec_Int_t * vEntries;
    word * pTruth;
    int i, Entry, nVars = p->nVars;
    int nEntries = Vec_MemEntryNum(p->vTtMem);
    if ( nEntries == 0 )
    {
        printf( "There is not truth tables.\n" );
        return;
    }
    pFile = fopen( pFileName, "wb" );
    if ( pFile == NULL )
    {
        printf( "The file cannot be opened.\n" );
        return;
    }
    p->vSupps = Vec_StrAlloc( nEntries );
    Vec_MemForEachEntry( p->vTtMem, pTruth, i )
        Vec_StrPush( p->vSupps, (char)Abc_TtSupportSize(pTruth, nVars) );
    vEntries = Vec_IntStartNatural( nEntries );
1359
    qsort( (void *)Vec_IntArray(vEntries), (size_t)nEntries, sizeof(int), (int(*)(const void *,const void *))Abc_NtkRecTruthCompare );
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
    Vec_StrFreeP( &p->vSupps );
    // write the file
    Vec_IntForEachEntry( vEntries, Entry, i )
    {
        pTruth = Vec_MemReadEntry(p->vTtMem, Entry);
        if ( fBinary )
        {
            fwrite( pTruth, 1, sizeof(word) * p->nWords, pFile );
            continue;
        }
        Extra_PrintHex( pFile, (unsigned *)pTruth, nVars );
        fprintf( pFile, "  " );
1372
//        Kit_DsdWriteFromTruth( pBuffer, (unsigned *)pTruth, nVars );
1373
        Dau_DsdDecompose( pTruth, p->nVars, 0, (int)(nVars <= 10), pBuffer );
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
        fprintf( pFile, "%s\n", pBuffer );
    }
    fclose( pFile );
    Vec_IntFree( vEntries );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
1391
int Abc_NtkRecInputNum3()
1392
{
1393
    return Gia_ManCiNum(s_pMan3->pGia);
1394 1395 1396 1397 1398 1399 1400
}
int Abc_NtkRecIsRunning3()
{
    return s_pMan3 != NULL;
}
Gia_Man_t * Abc_NtkRecGetGia3()
{
1401
    abctime clk = Abc_Clock();
1402
    printf( "Before normalizing: Library has %d classes and %d AIG subgraphs with %d AND nodes.\n", 
1403
        Vec_MemEntryNum(s_pMan3->vTtMem), Gia_ManPoNum(s_pMan3->pGia), Gia_ManAndNum(s_pMan3->pGia) );
1404
    Lms_GiaNormalize( s_pMan3 );
1405
    printf( "After normalizing:  Library has %d classes and %d AIG subgraphs with %d AND nodes.\n", 
1406
        Vec_MemEntryNum(s_pMan3->vTtMem), Gia_ManPoNum(s_pMan3->pGia), Gia_ManAndNum(s_pMan3->pGia) );
1407
    Abc_PrintTime( 1, "Normalization runtime", Abc_Clock() - clk );
1408
    s_pMan3->fLibConstr = 0;
1409 1410
    return s_pMan3->pGia;
}
1411
void Abc_NtkRecPs3(int fPrintLib)
1412
{
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
    Lms_ManPrint( s_pMan3 );
}
void Abc_NtkRecStart3( Gia_Man_t * p, int nVars, int nCuts, int fFuncOnly, int fVerbose )
{
    assert( s_pMan3 == NULL );
    s_pMan3 = Lms_ManStart( p, nVars, nCuts, fFuncOnly, fVerbose );
}

void Abc_NtkRecStop3()
{
    assert( s_pMan3 != NULL );
    Lms_ManStop( s_pMan3 );
    s_pMan3 = NULL;
1426
}
1427 1428 1429 1430 1431 1432

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


Alan Mishchenko committed
1433
ABC_NAMESPACE_IMPL_END