From 6b44b18e69f4e26249140e10c459615a77b32fc5 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 4 Aug 2006 08:01:00 -0700 Subject: [PATCH] Version abc60804 --- src/base/abci/abc.c | 34 ++- src/base/abci/abcIvy.c | 6 +- src/base/abci/abcSat.c | 2 +- src/base/abci/abcTiming.c | 5 +- src/base/main/mainFrame.c | 4 +- src/misc/nm/nmApi.c | 7 +- src/misc/nm/nmInt.h | 2 + src/misc/nm/nmTable.c | 106 +++++++- src/misc/vec/vecInt.h | 22 ++ src/opt/cut/abcCut.c | 491 ++++++++++++++++++++++++++++++++++ src/opt/cut/cut60720.zip | Bin 0 -> 31142 bytes src/opt/cut/cut60721.zip | Bin 0 -> 42872 bytes src/opt/cut/cutNode.c | 4 +- src/sat/msat/msatActivity.c | 2 +- src/sat/msat/msatInt.h | 2 +- src/sat/msat/msatSolverApi.c | 8 +- src/temp/ivy/ivy.h | 15 +- src/temp/ivy/ivyCheck.c | 90 ++++++- src/temp/ivy/ivyCut.c | 27 +- src/temp/ivy/ivyDfs.c | 4 +- src/temp/ivy/ivyFanout.c | 293 ++++++++++---------- src/temp/ivy/ivyIsop.c | 223 +++++++-------- src/temp/ivy/ivyMan.c | 14 +- src/temp/ivy/ivyMem.c | 6 +- src/temp/ivy/ivyObj.c | 53 ++-- src/temp/ivy/ivyResyn.c | 41 +++ src/temp/ivy/ivyRwrPre.c | 2 +- src/temp/ivy/ivySeq.c | 2 +- src/temp/ivy/ivyUtil.c | 4 +- src/temp/player/player.h | 3 +- src/temp/player/playerMan.c | 2 +- src/temp/player/playerToAbc.c | 67 +++-- src/temp/vec/vecInt.h | 44 +-- src/temp/vec/vecPtr.h | 30 ++- 34 files changed, 1231 insertions(+), 384 deletions(-) create mode 100644 src/opt/cut/abcCut.c create mode 100644 src/opt/cut/cut60720.zip create mode 100644 src/opt/cut/cut60721.zip diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 7bee7f400..bb8f56586 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -4487,22 +4487,26 @@ int Abc_CommandXyz( Abc_Frame_t * pAbc, int argc, char ** argv ) int nPlaMax; int RankCost; int fFastMode; + int fRewriting; + int fSynthesis; int fVerbose; -// extern Abc_Ntk_t * Abc_NtkXyz( Abc_Ntk_t * pNtk, int nPlaMax, bool fUseEsop, bool fUseSop, bool fUseInvs, bool fVerbose ); - extern void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int fFastMode, int fVerbose ); +// extern Abc_Ntk_t * Abc_NtkXyz( Abc_Ntk_t * pNtk, int nPlaMax, bool fEsop, bool fSop, bool fInvs, bool fVerbose ); + extern void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int fFastMode, int fRewriting, int fSynthesis, int fVerbose ); pNtk = Abc_FrameReadNtk(pAbc); pOut = Abc_FrameReadOut(pAbc); pErr = Abc_FrameReadErr(pAbc); // set defaults - nLutMax = 8; - nPlaMax = 128; - RankCost = 96000; - fFastMode = 0; - fVerbose = 0; + nLutMax = 8; + nPlaMax = 128; + RankCost = 96000; + fFastMode = 1; + fRewriting = 1; + fSynthesis = 0; + fVerbose = 1; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "LPRfvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "LPRfrsvh" ) ) != EOF ) { switch ( c ) { @@ -4542,6 +4546,12 @@ int Abc_CommandXyz( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'f': fFastMode ^= 1; break; + case 'r': + fRewriting ^= 1; + break; + case 's': + fSynthesis ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -4570,8 +4580,8 @@ int Abc_CommandXyz( Abc_Frame_t * pAbc, int argc, char ** argv ) } // run the command -// pNtkRes = Abc_NtkXyz( pNtk, nPlaMax, 1, 0, fUseInvs, fVerbose ); - pNtkRes = Abc_NtkPlayer( pNtk, nLutMax, nPlaMax, RankCost, fFastMode, fVerbose ); +// pNtkRes = Abc_NtkXyz( pNtk, nPlaMax, 1, 0, fInvs, fVerbose ); + pNtkRes = Abc_NtkPlayer( pNtk, nLutMax, nPlaMax, RankCost, fFastMode, fRewriting, fSynthesis, fVerbose ); if ( pNtkRes == NULL ) { fprintf( pErr, "Command has failed.\n" ); @@ -4582,12 +4592,14 @@ int Abc_CommandXyz( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - fprintf( pErr, "usage: xyz [-L num] [-P num] [-R num] [-fvh]\n" ); + fprintf( pErr, "usage: xyz [-L num] [-P num] [-R num] [-frsvh]\n" ); fprintf( pErr, "\t specilized LUT/PLA decomposition\n" ); fprintf( pErr, "\t-L num : maximum number of LUT inputs (2<=num<=8) [default = %d]\n", nLutMax ); fprintf( pErr, "\t-P num : maximum number of PLA inputs/cubes (8<=num<=128) [default = %d]\n", nPlaMax ); fprintf( pErr, "\t-R num : maximum are of one decomposition rank [default = %d]\n", RankCost ); fprintf( pErr, "\t-f : toggle using fast LUT mapping mode [default = %s]\n", fFastMode? "yes": "no" ); + fprintf( pErr, "\t-r : toggle using one pass of AIG rewriting [default = %s]\n", fRewriting? "yes": "no" ); + fprintf( pErr, "\t-s : toggle using synthesis by AIG rewriting [default = %s]\n", fSynthesis? "yes": "no" ); fprintf( pErr, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); fprintf( pErr, "\t-h : print the command usage\n"); return 1; diff --git a/src/base/abci/abcIvy.c b/src/base/abci/abcIvy.c index a3ffcf4ed..380b3f8b4 100644 --- a/src/base/abci/abcIvy.c +++ b/src/base/abci/abcIvy.c @@ -343,9 +343,11 @@ Abc_Ntk_t * Abc_NtkIvy( Abc_Ntk_t * pNtk ) // Ivy_ManRequiredLevels( pMan ); - Pla_ManFastLutMap( pMan, 8 ); - Ivy_ManStop( pMan ); +// Pla_ManFastLutMap( pMan, 8 ); +// Ivy_ManStop( pMan ); return NULL; + + /* // convert from the AIG manager pNtkAig = Abc_NtkFromAig( pNtk, pMan ); diff --git a/src/base/abci/abcSat.c b/src/base/abci/abcSat.c index f447516fb..b8491d061 100644 --- a/src/base/abci/abcSat.c +++ b/src/base/abci/abcSat.c @@ -408,7 +408,7 @@ void Abc_NtkCollectSupergate( Abc_Obj_t * pNode, int fStopAtMux, Vec_Ptr_t * vNo int Abc_NtkNodeFactor( Abc_Obj_t * pObj, int nLevelMax ) { // nLevelMax = ((nLevelMax)/2)*3; - assert( pObj->Level <= nLevelMax ); + assert( (int)pObj->Level <= nLevelMax ); // return (int)(100000000.0 * pow(0.999, nLevelMax - pObj->Level)); return (int)(100000000.0 * (1 + 0.01 * pObj->Level)); // return (int)(100000000.0 / ((nLevelMax)/2)*3 - pObj->Level); diff --git a/src/base/abci/abcTiming.c b/src/base/abci/abcTiming.c index a40954bd5..d2d731d91 100644 --- a/src/base/abci/abcTiming.c +++ b/src/base/abci/abcTiming.c @@ -647,9 +647,10 @@ void Abc_NtkStartReverseLevels( Abc_Ntk_t * pNtk ) Vec_Ptr_t * vNodes; Abc_Obj_t * pObj, * pFanout; int i, k, nLevelsCur; - assert( Abc_NtkIsStrash(pNtk) ); +// assert( Abc_NtkIsStrash(pNtk) ); // remember the maximum number of direct levels - pNtk->LevelMax = Abc_AigGetLevelNum(pNtk); +// pNtk->LevelMax = Abc_AigGetLevelNum(pNtk); + pNtk->LevelMax = Abc_NtkGetLevelNum(pNtk); // start the reverse levels pNtk->vLevelsR = Vec_IntAlloc( 0 ); Vec_IntFill( pNtk->vLevelsR, Abc_NtkObjNumMax(pNtk), 0 ); diff --git a/src/base/main/mainFrame.c b/src/base/main/mainFrame.c index ecf77f706..5c4a06753 100644 --- a/src/base/main/mainFrame.c +++ b/src/base/main/mainFrame.c @@ -136,11 +136,11 @@ void Abc_FrameDeallocate( Abc_Frame_t * p ) { extern void Rwt_ManGlobalStop(); extern void undefine_cube_size(); - extern void Ivy_TruthManStop(); +// extern void Ivy_TruthManStop(); // Abc_HManStop(); undefine_cube_size(); Rwt_ManGlobalStop(); - Ivy_TruthManStop(); +// Ivy_TruthManStop(); if ( p->pManDec ) Dec_ManStop( p->pManDec ); if ( p->dd ) Extra_StopManager( p->dd ); Abc_FrameDeleteAllNetworks( p ); diff --git a/src/misc/nm/nmApi.c b/src/misc/nm/nmApi.c index e44d1ef9e..120dbe91f 100644 --- a/src/misc/nm/nmApi.c +++ b/src/misc/nm/nmApi.c @@ -46,10 +46,10 @@ Nm_Man_t * Nm_ManCreate( int nSize ) p = ALLOC( Nm_Man_t, 1 ); memset( p, 0, sizeof(Nm_Man_t) ); // set the parameters - p->nSizeFactor = 4; // determined how much larger the table should be compared to data in it - p->nGrowthFactor = 4; // determined how much the table grows after resizing + p->nSizeFactor = 2; // determined how much larger the table should be compared to data in it + p->nGrowthFactor = 3; // determined how much the table grows after resizing // allocate and clean the bins - p->nBins = Cudd_PrimeNm(p->nSizeFactor*nSize); + p->nBins = Cudd_PrimeNm(nSize); p->pBinsI2N = ALLOC( Nm_Entry_t *, p->nBins ); p->pBinsN2I = ALLOC( Nm_Entry_t *, p->nBins ); memset( p->pBinsI2N, 0, sizeof(Nm_Entry_t *) * p->nBins ); @@ -127,6 +127,7 @@ char * Nm_ManStoreIdName( Nm_Man_t * p, int ObjId, char * pName, char * pSuffix nEntrySize = sizeof(Nm_Entry_t) + strlen(pName) + (pSuffix?strlen(pSuffix):0) + 1; nEntrySize = (nEntrySize / 4 + ((nEntrySize % 4) > 0)) * 4; pEntry = (Nm_Entry_t *)Extra_MmFlexEntryFetch( p->pMem, nEntrySize ); + pEntry->pNextI2N = pEntry->pNextN2I = NULL; pEntry->ObjId = ObjId; sprintf( pEntry->Name, "%s%s", pName, pSuffix? pSuffix : "" ); // add the entry to the hash table diff --git a/src/misc/nm/nmInt.h b/src/misc/nm/nmInt.h index 439019932..8356a4cbd 100644 --- a/src/misc/nm/nmInt.h +++ b/src/misc/nm/nmInt.h @@ -45,6 +45,8 @@ typedef struct Nm_Entry_t_ Nm_Entry_t; struct Nm_Entry_t_ { int ObjId; // object ID + Nm_Entry_t * pNextI2N; // the next entry in the ID hash table + Nm_Entry_t * pNextN2I; // the next entry in the name hash table char Name[0]; // name of the object }; diff --git a/src/misc/nm/nmTable.c b/src/misc/nm/nmTable.c index 4243244d2..4eeaf610a 100644 --- a/src/misc/nm/nmTable.c +++ b/src/misc/nm/nmTable.c @@ -44,7 +44,7 @@ static unsigned Nm_HashString( char * pName, int TableSize ) }; unsigned i, Key = 0; for ( i = 0; pName[i] != '\0'; i++ ) - Key ^= s_Primes[i%10]*pName[i]*pName[i]*pName[i]; + Key ^= s_Primes[i%10]*pName[i]*pName[i]; return Key % TableSize; } @@ -67,13 +67,16 @@ static void Nm_ManResize( Nm_Man_t * p ); ***********************************************************************/ int Nm_ManTableAdd( Nm_Man_t * p, Nm_Entry_t * pEntry ) { - int i; + Nm_Entry_t ** ppSpot; +// int i; // resize the tables if needed - if ( p->nEntries * p->nSizeFactor > p->nBins ) +// if ( p->nEntries * p->nSizeFactor > p->nBins ) + if ( p->nEntries > p->nBins * p->nSizeFactor ) { // Nm_ManPrintTables( p ); Nm_ManResize( p ); } +/* // hash it by ID for ( i = Nm_HashNumber(pEntry->ObjId, p->nBins); p->pBinsI2N[i]; i = (i+1) % p->nBins ) if ( p->pBinsI2N[i] == pEntry ) @@ -86,6 +89,15 @@ int Nm_ManTableAdd( Nm_Man_t * p, Nm_Entry_t * pEntry ) return 0; assert( p->pBinsN2I[i] == NULL ); p->pBinsN2I[i] = pEntry; +*/ + ppSpot = p->pBinsI2N + Nm_HashNumber(pEntry->ObjId, p->nBins); + pEntry->pNextI2N = *ppSpot; + *ppSpot = pEntry; + + ppSpot = p->pBinsN2I + Nm_HashString(pEntry->Name, p->nBins); + pEntry->pNextN2I = *ppSpot; + *ppSpot = pEntry; + // report successfully added entry p->nEntries++; return 1; @@ -121,10 +133,16 @@ int Nm_ManTableDelete( Nm_Man_t * p, Nm_Entry_t * pEntry ) ***********************************************************************/ Nm_Entry_t * Nm_ManTableLookupId( Nm_Man_t * p, int ObjId ) { - int i; + Nm_Entry_t * pEntry; +// int i; +/* for ( i = Nm_HashNumber(ObjId, p->nBins); p->pBinsI2N[i]; i = (i+1) % p->nBins ) if ( p->pBinsI2N[i]->ObjId == ObjId ) return p->pBinsI2N[i]; +*/ + for ( pEntry = p->pBinsI2N[ Nm_HashNumber(ObjId, p->nBins) ]; pEntry; pEntry = pEntry->pNextI2N ) + if ( pEntry->ObjId == ObjId ) + return pEntry; return NULL; } @@ -141,9 +159,10 @@ Nm_Entry_t * Nm_ManTableLookupId( Nm_Man_t * p, int ObjId ) ***********************************************************************/ Nm_Entry_t * Nm_ManTableLookupName( Nm_Man_t * p, char * pName, Nm_Entry_t ** ppSecond ) { - Nm_Entry_t * pFirst, * pSecond; - int i, Counter = 0; + Nm_Entry_t * pFirst, * pSecond, * pEntry; + int Counter = 0; pFirst = pSecond = NULL; +/* for ( i = Nm_HashString(pName, p->nBins); p->pBinsN2I[i]; i = (i+1) % p->nBins ) if ( strcmp(p->pBinsN2I[i]->Name, pName) == 0 ) { @@ -158,12 +177,60 @@ Nm_Entry_t * Nm_ManTableLookupName( Nm_Man_t * p, char * pName, Nm_Entry_t ** pp Counter++; if ( Counter > 100 ) printf( "%d ", Counter ); +*/ + for ( pEntry = p->pBinsN2I[ Nm_HashString(pName, p->nBins) ]; pEntry; pEntry = pEntry->pNextN2I ) + if ( strcmp(pEntry->Name, pName) == 0 ) + { + if ( pFirst == NULL ) + pFirst = pEntry; + else if ( pSecond == NULL ) + pSecond = pEntry; + else + assert( 0 ); // name appears more than 2 times + } + // save the names if ( ppSecond ) *ppSecond = pSecond; return pFirst; } +/**Function************************************************************* + + Synopsis [Profiles hash tables.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Nm_ManProfile( Nm_Man_t * p ) +{ + Nm_Entry_t * pEntry; + int Counter, e; + printf( "I2N table: " ); + for ( e = 0; e < p->nBins; e++ ) + { + Counter = 0; + for ( pEntry = p->pBinsI2N[e]; pEntry; pEntry = pEntry->pNextI2N ) + Counter++; + printf( "%d ", Counter ); + } + printf( "\n" ); + printf( "N2I table: " ); + for ( e = 0; e < p->nBins; e++ ) + { + Counter = 0; + for ( pEntry = p->pBinsN2I[e]; pEntry; pEntry = pEntry->pNextN2I ) + Counter++; + printf( "%d ", Counter ); + } + printf( "\n" ); +} + + /**Function************************************************************* @@ -178,8 +245,8 @@ Nm_Entry_t * Nm_ManTableLookupName( Nm_Man_t * p, char * pName, Nm_Entry_t ** pp ***********************************************************************/ void Nm_ManResize( Nm_Man_t * p ) { - Nm_Entry_t ** pBinsNewI2N, ** pBinsNewN2I, * pEntry; - int nBinsNew, Counter, e, i, clk; + Nm_Entry_t ** pBinsNewI2N, ** pBinsNewN2I, * pEntry, * pEntry2, ** ppSpot; + int nBinsNew, Counter, e, clk; clk = clock(); // get the new table size @@ -192,12 +259,13 @@ clk = clock(); // rehash the entries from the old table Counter = 0; for ( e = 0; e < p->nBins; e++ ) + for ( pEntry = p->pBinsI2N[e], pEntry2 = pEntry? pEntry->pNextI2N : NULL; + pEntry; pEntry = pEntry2, pEntry2 = pEntry? pEntry->pNextI2N : NULL ) { - pEntry = p->pBinsI2N[e]; - if ( pEntry == NULL ) - continue; - Counter++; - +// pEntry = p->pBinsI2N[e]; +// if ( pEntry == NULL ) +// continue; +/* // hash it by ID for ( i = Nm_HashNumber(pEntry->ObjId, nBinsNew); pBinsNewI2N[i]; i = (i+1) % nBinsNew ) if ( pBinsNewI2N[i] == pEntry ) @@ -210,6 +278,16 @@ clk = clock(); assert( 0 ); assert( pBinsNewN2I[i] == NULL ); pBinsNewN2I[i] = pEntry; +*/ + ppSpot = pBinsNewI2N + Nm_HashNumber(pEntry->ObjId, nBinsNew); + pEntry->pNextI2N = *ppSpot; + *ppSpot = pEntry; + + ppSpot = pBinsNewN2I + Nm_HashString(pEntry->Name, nBinsNew); + pEntry->pNextN2I = *ppSpot; + *ppSpot = pEntry; + + Counter++; } assert( Counter == p->nEntries ); // printf( "Increasing the structural table size from %6d to %6d. ", p->nBins, nBinsNew ); @@ -220,10 +298,10 @@ clk = clock(); p->pBinsI2N = pBinsNewI2N; p->pBinsN2I = pBinsNewN2I; p->nBins = nBinsNew; +// Nm_ManProfile( p ); } - /**Function************************************************************* Synopsis [Returns the smallest prime larger than the number.] diff --git a/src/misc/vec/vecInt.h b/src/misc/vec/vecInt.h index 4f193cf29..4a97fc919 100644 --- a/src/misc/vec/vecInt.h +++ b/src/misc/vec/vecInt.h @@ -581,6 +581,28 @@ static inline int Vec_IntPushUnique( Vec_Int_t * p, int Entry ) return 0; } +/**Function************************************************************* + + Synopsis [Returns the pointer to the next nWords entries in the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned * Vec_IntFetch( Vec_Int_t * p, int nWords ) +{ + p->nSize += nWords; + if ( p->nSize > p->nCap ) + { +// Vec_IntGrow( p, 2 * p->nSize ); + return NULL; + } + return ((unsigned *)p->pArray) + p->nSize - nWords; +} + /**Function************************************************************* Synopsis [Returns the last entry and removes it from the list.] diff --git a/src/opt/cut/abcCut.c b/src/opt/cut/abcCut.c new file mode 100644 index 000000000..b4b879a30 --- /dev/null +++ b/src/opt/cut/abcCut.c @@ -0,0 +1,491 @@ +/**CFile**************************************************************** + + FileName [abcCut.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Network and node package.] + + Synopsis [Interface to cut computation.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: abcCut.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "abc.h" +#include "cut.h" +#include "seqInt.h" + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +static void Abc_NtkPrintCuts( void * p, Abc_Ntk_t * pNtk, int fSeq ); +static void Abc_NtkPrintCuts_( void * p, Abc_Ntk_t * pNtk, int fSeq ); + + +extern int nTotal, nGood, nEqual; + +// temporary +//Vec_Int_t * Abc_NtkGetNodeAttributes( Abc_Ntk_t * pNtk ) { return NULL; } +Vec_Int_t * Abc_NtkGetNodeAttributes( Abc_Ntk_t * pNtk ) +{ + Vec_Int_t * vAttrs = Vec_IntStart( Abc_NtkObjNumMax(pNtk) + 1 ); + int i; + Abc_Obj_t * pObj; + +// Abc_NtkForEachCi( pNtk, pObj, i ) +// Vec_IntWriteEntry( vAttrs, pObj->Id, 1 ); + + Abc_NtkForEachObj( pNtk, pObj, i ) + { +// if ( Abc_ObjIsNode(pObj) && (rand() % 4 == 0) ) + if ( Abc_ObjIsNode(pObj) && Abc_ObjFanoutNum(pObj) > 1 && !Abc_NodeIsMuxControlType(pObj) && (rand() % 3 == 0) ) + Vec_IntWriteEntry( vAttrs, pObj->Id, 1 ); + } + return vAttrs; +} + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Man_t * Abc_NtkCuts( Abc_Ntk_t * pNtk, Cut_Params_t * pParams ) +{ + ProgressBar * pProgress; + Cut_Man_t * p; + Abc_Obj_t * pObj, * pNode; + Vec_Ptr_t * vNodes; + Vec_Int_t * vChoices; + int i; + int clk = clock(); + + extern void Abc_NtkBalanceAttach( Abc_Ntk_t * pNtk ); + extern void Abc_NtkBalanceDetach( Abc_Ntk_t * pNtk ); + + nTotal = nGood = nEqual = 0; + + assert( Abc_NtkIsStrash(pNtk) ); + // start the manager + pParams->nIdsMax = Abc_NtkObjNumMax( pNtk ); + p = Cut_ManStart( pParams ); + // compute node attributes if local or global cuts are requested + if ( pParams->fGlobal || pParams->fLocal ) + { + extern Vec_Int_t * Abc_NtkGetNodeAttributes( Abc_Ntk_t * pNtk ); + Cut_ManSetNodeAttrs( p, Abc_NtkGetNodeAttributes(pNtk) ); + } + // prepare for cut dropping + if ( pParams->fDrop ) + Cut_ManSetFanoutCounts( p, Abc_NtkFanoutCounts(pNtk) ); + // set cuts for PIs + Abc_NtkForEachCi( pNtk, pObj, i ) + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Cut_NodeSetTriv( p, pObj->Id ); + // compute cuts for internal nodes + vNodes = Abc_AigDfs( pNtk, 0, 1 ); // collects POs + vChoices = Vec_IntAlloc( 100 ); + pProgress = Extra_ProgressBarStart( stdout, Vec_PtrSize(vNodes) ); + Vec_PtrForEachEntry( vNodes, pObj, i ) + { + // when we reached a CO, it is time to deallocate the cuts + if ( Abc_ObjIsCo(pObj) ) + { + if ( pParams->fDrop ) + Cut_NodeTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + continue; + } + // skip constant node, it has no cuts + if ( Abc_NodeIsConst(pObj) ) + continue; + Extra_ProgressBarUpdate( pProgress, i, NULL ); + // compute the cuts to the internal node + Abc_NodeGetCuts( p, pObj, pParams->fDag, pParams->fTree ); + // consider dropping the fanins cuts + if ( pParams->fDrop ) + { + Cut_NodeTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + Cut_NodeTryDroppingCuts( p, Abc_ObjFaninId1(pObj) ); + } + // add cuts due to choices + if ( Abc_NodeIsAigChoice(pObj) ) + { + Vec_IntClear( vChoices ); + for ( pNode = pObj; pNode; pNode = pNode->pData ) + Vec_IntPush( vChoices, pNode->Id ); + Cut_NodeUnionCuts( p, vChoices ); + } + } + Extra_ProgressBarStop( pProgress ); + Vec_PtrFree( vNodes ); + Vec_IntFree( vChoices ); +PRT( "Total", clock() - clk ); +//Abc_NtkPrintCuts( p, pNtk, 0 ); +// Cut_ManPrintStatsToFile( p, pNtk->pSpec, clock() - clk ); + + // temporary printout of stats + if ( nTotal ) + printf( "Total cuts = %d. Good cuts = %d. Ratio = %5.2f\n", nTotal, nGood, ((double)nGood)/nTotal ); + return p; +} + +/**Function************************************************************* + + Synopsis [Cut computation using the oracle.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkCutsOracle( Abc_Ntk_t * pNtk, Cut_Oracle_t * p ) +{ + Abc_Obj_t * pObj; + Vec_Ptr_t * vNodes; + int i, clk = clock(); + int fDrop = Cut_OracleReadDrop(p); + + assert( Abc_NtkIsStrash(pNtk) ); + + // prepare cut droppping + if ( fDrop ) + Cut_OracleSetFanoutCounts( p, Abc_NtkFanoutCounts(pNtk) ); + + // set cuts for PIs + Abc_NtkForEachCi( pNtk, pObj, i ) + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Cut_OracleNodeSetTriv( p, pObj->Id ); + + // compute cuts for internal nodes + vNodes = Abc_AigDfs( pNtk, 0, 1 ); // collects POs + Vec_PtrForEachEntry( vNodes, pObj, i ) + { + // when we reached a CO, it is time to deallocate the cuts + if ( Abc_ObjIsCo(pObj) ) + { + if ( fDrop ) + Cut_OracleTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + continue; + } + // skip constant node, it has no cuts + if ( Abc_NodeIsConst(pObj) ) + continue; + // compute the cuts to the internal node + Cut_OracleComputeCuts( p, pObj->Id, Abc_ObjFaninId0(pObj), Abc_ObjFaninId1(pObj), + Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj) ); + // consider dropping the fanins cuts + if ( fDrop ) + { + Cut_OracleTryDroppingCuts( p, Abc_ObjFaninId0(pObj) ); + Cut_OracleTryDroppingCuts( p, Abc_ObjFaninId1(pObj) ); + } + } + Vec_PtrFree( vNodes ); +//PRT( "Total", clock() - clk ); +//Abc_NtkPrintCuts_( p, pNtk, 0 ); +} + + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Cut_Man_t * Abc_NtkSeqCuts( Abc_Ntk_t * pNtk, Cut_Params_t * pParams ) +{ + Cut_Man_t * p; + Abc_Obj_t * pObj, * pNode; + int i, nIters, fStatus; + Vec_Int_t * vChoices; + int clk = clock(); + + assert( Abc_NtkIsSeq(pNtk) ); + assert( pParams->fSeq ); +// assert( Abc_NtkIsDfsOrdered(pNtk) ); + + // start the manager + pParams->nIdsMax = Abc_NtkObjNumMax( pNtk ); + pParams->nCutSet = Abc_NtkCutSetNodeNum( pNtk ); + p = Cut_ManStart( pParams ); + + // set cuts for the constant node and the PIs + pObj = Abc_NtkConst1(pNtk); + if ( Abc_ObjFanoutNum(pObj) > 0 ) + Cut_NodeSetTriv( p, pObj->Id ); + Abc_NtkForEachPi( pNtk, pObj, i ) + { +//printf( "Setting trivial cut %d.\n", pObj->Id ); + Cut_NodeSetTriv( p, pObj->Id ); + } + // label the cutset nodes and set their number in the array + // assign the elementary cuts to the cutset nodes + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + { + assert( pObj->fMarkC == 0 ); + pObj->fMarkC = 1; + pObj->pCopy = (Abc_Obj_t *)i; + Cut_NodeSetTriv( p, pObj->Id ); +//printf( "Setting trivial cut %d.\n", pObj->Id ); + } + + // process the nodes + vChoices = Vec_IntAlloc( 100 ); + for ( nIters = 0; nIters < 10; nIters++ ) + { +//printf( "ITERATION %d:\n", nIters ); + // compute the cuts for the internal nodes + Abc_AigForEachAnd( pNtk, pObj, i ) + { + Abc_NodeGetCutsSeq( p, pObj, nIters==0 ); + // add cuts due to choices + if ( Abc_NodeIsAigChoice(pObj) ) + { + Vec_IntClear( vChoices ); + for ( pNode = pObj; pNode; pNode = pNode->pData ) + Vec_IntPush( vChoices, pNode->Id ); + Cut_NodeUnionCutsSeq( p, vChoices, (pObj->fMarkC ? (int)pObj->pCopy : -1), nIters==0 ); + } + } + // merge the new cuts with the old cuts + Abc_NtkForEachPi( pNtk, pObj, i ) + Cut_NodeNewMergeWithOld( p, pObj->Id ); + Abc_AigForEachAnd( pNtk, pObj, i ) + Cut_NodeNewMergeWithOld( p, pObj->Id ); + // for the cutset, transfer temp cuts to new cuts + fStatus = 0; + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + fStatus |= Cut_NodeTempTransferToNew( p, pObj->Id, i ); + if ( fStatus == 0 ) + break; + } + Vec_IntFree( vChoices ); + + // if the status is not finished, transfer new to old for the cutset + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + Cut_NodeNewMergeWithOld( p, pObj->Id ); + + // transfer the old cuts to the new positions + Abc_NtkForEachObj( pNtk, pObj, i ) + Cut_NodeOldTransferToNew( p, pObj->Id ); + + // unlabel the cutset nodes + Abc_SeqForEachCutsetNode( pNtk, pObj, i ) + pObj->fMarkC = 0; +if ( pParams->fVerbose ) +{ +PRT( "Total", clock() - clk ); +printf( "Converged after %d iterations.\n", nIters ); +} +//Abc_NtkPrintCuts( p, pNtk, 1 ); + return p; +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Abc_NodeGetCutsRecursive( void * p, Abc_Obj_t * pObj, int fDag, int fTree ) +{ + void * pList; + if ( pList = Abc_NodeReadCuts( p, pObj ) ) + return pList; + Abc_NodeGetCutsRecursive( p, Abc_ObjFanin0(pObj), fDag, fTree ); + Abc_NodeGetCutsRecursive( p, Abc_ObjFanin1(pObj), fDag, fTree ); + return Abc_NodeGetCuts( p, pObj, fDag, fTree ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Abc_NodeGetCuts( void * p, Abc_Obj_t * pObj, int fDag, int fTree ) +{ + Abc_Obj_t * pFanin; + int fDagNode, fTriv, TreeCode = 0; +// assert( Abc_NtkIsStrash(pObj->pNtk) ); + assert( Abc_ObjFaninNum(pObj) == 2 ); + + + // check if the node is a DAG node + fDagNode = (Abc_ObjFanoutNum(pObj) > 1 && !Abc_NodeIsMuxControlType(pObj)); + // increment the counter of DAG nodes + if ( fDagNode ) Cut_ManIncrementDagNodes( p ); + // add the trivial cut if the node is a DAG node, or if we compute all cuts + fTriv = fDagNode || !fDag; + // check if fanins are DAG nodes + if ( fTree ) + { + pFanin = Abc_ObjFanin0(pObj); + TreeCode |= (Abc_ObjFanoutNum(pFanin) > 1 && !Abc_NodeIsMuxControlType(pFanin)); + pFanin = Abc_ObjFanin1(pObj); + TreeCode |= ((Abc_ObjFanoutNum(pFanin) > 1 && !Abc_NodeIsMuxControlType(pFanin)) << 1); + } + + + // changes due to the global/local cut computation + { + Cut_Params_t * pParams = Cut_ManReadParams(p); + if ( pParams->fLocal ) + { + Vec_Int_t * vNodeAttrs = Cut_ManReadNodeAttrs(p); + fDagNode = Vec_IntEntry( vNodeAttrs, pObj->Id ); + if ( fDagNode ) Cut_ManIncrementDagNodes( p ); +// fTriv = fDagNode || !pParams->fGlobal; + fTriv = !Vec_IntEntry( vNodeAttrs, pObj->Id ); + TreeCode = 0; + pFanin = Abc_ObjFanin0(pObj); + TreeCode |= Vec_IntEntry( vNodeAttrs, pFanin->Id ); + pFanin = Abc_ObjFanin1(pObj); + TreeCode |= (Vec_IntEntry( vNodeAttrs, pFanin->Id ) << 1); + } + } + return Cut_NodeComputeCuts( p, pObj->Id, Abc_ObjFaninId0(pObj), Abc_ObjFaninId1(pObj), + Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj), fTriv, TreeCode ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NodeGetCutsSeq( void * p, Abc_Obj_t * pObj, int fTriv ) +{ + int CutSetNum; + assert( Abc_NtkIsSeq(pObj->pNtk) ); + assert( Abc_ObjFaninNum(pObj) == 2 ); + fTriv = pObj->fMarkC ? 0 : fTriv; + CutSetNum = pObj->fMarkC ? (int)pObj->pCopy : -1; + Cut_NodeComputeCutsSeq( p, pObj->Id, Abc_ObjFaninId0(pObj), Abc_ObjFaninId1(pObj), + Abc_ObjFaninC0(pObj), Abc_ObjFaninC1(pObj), Seq_ObjFaninL0(pObj), Seq_ObjFaninL1(pObj), fTriv, CutSetNum ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void * Abc_NodeReadCuts( void * p, Abc_Obj_t * pObj ) +{ + return Cut_NodeReadCutsNew( p, pObj->Id ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NodeFreeCuts( void * p, Abc_Obj_t * pObj ) +{ + Cut_NodeFreeCuts( p, pObj->Id ); +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkPrintCuts( void * p, Abc_Ntk_t * pNtk, int fSeq ) +{ + Cut_Man_t * pMan = p; + Cut_Cut_t * pList; + Abc_Obj_t * pObj; + int i; + printf( "Cuts of the network:\n" ); + Abc_NtkForEachObj( pNtk, pObj, i ) + { + pList = Abc_NodeReadCuts( p, pObj ); + printf( "Node %s:\n", Abc_ObjName(pObj) ); + Cut_CutPrintList( pList, fSeq ); + } +} + +/**Function************************************************************* + + Synopsis [Computes the cuts for the network.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkPrintCuts_( void * p, Abc_Ntk_t * pNtk, int fSeq ) +{ + Cut_Man_t * pMan = p; + Cut_Cut_t * pList; + Abc_Obj_t * pObj; + pObj = Abc_NtkObj( pNtk, 2 * Abc_NtkObjNum(pNtk) / 3 ); + pList = Abc_NodeReadCuts( p, pObj ); + printf( "Node %s:\n", Abc_ObjName(pObj) ); + Cut_CutPrintList( pList, fSeq ); +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + diff --git a/src/opt/cut/cut60720.zip b/src/opt/cut/cut60720.zip new file mode 100644 index 0000000000000000000000000000000000000000..86ad67262c23a35ba5204db31081153d20c351e9 GIT binary patch literal 31142 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 literal 0 HcmV?d00001 diff --git a/src/opt/cut/cut60721.zip b/src/opt/cut/cut60721.zip new file mode 100644 index 0000000000000000000000000000000000000000..d55ccfd07b50f99387f0147be28e0da1f7b6ab4f GIT binary patch literal 42872 zcmY(JLzG~_wx-jzZQHi(O53(=+qP}nc2?T9t*+Z|t#`X)a0W4qbt1m~LqQrC1O)&H z00LlL`Cf#dFa6@#j5=J_mTti|%3}A^zvaxo&1`#p z^%R#O?bdt0zO%7I1VRaW4N7{az0NMjAN!Im-+1#7Anr_PRp)v8@p&|y#}sx4PM@hb z%hAxo*il57#V{6|ek+LTx~>c|Yhz|BPx@U&7<2P&Pxs;elb$H>_lC5{!`ELVAt?ZT z!QPNNS%lBwAe`feD4duv{ANC?C<7nqUi(>llejE;E*tat#pv*3hzB|hcOnVVO2ip zo^K)1YKJhO)qLCXx9GW4cH`RTp1&br1e91j5BMR8p!tzS9@^qN#v>LxNJS5b+N&we z6mpziZSb5{LLJ4{t|j*jF6yS4lv_8dC5v4JUqmUu*>#SI?H$GmB zF`E6$-f@w1>bfRI(#Fnb09GJeavzS{!7(3td~+0h{k3YpXW!W3c)sO8LxJ9d$i}@jGZ}Xg!|{d;riVH zL`a#{E(m%y>qr;?Nx-D`=Km!Tf;%gx8~i_9h=t;NEP!IBeqGrBg~ zq}#HjiRi4bAC}VW?s`GFTAtMBbb^F}0a>OY%NpwTGDD7d0gH_KY!@k775`&Kl1hdt z#4fHI+}~*jA2Zt$S0PNBCBSasyqo+5kSRq|hORgl-eT&`$=O9=0O3K=J-vP6y^@^f z2F|k38Qi-mispBj4DA^(Yv$Ni4fBn`7XY7-Mlsr%8!bDA6aA_H_W^ISG86&i7Jblx@o{>--{3SJ2KY*TqOp!HbzhsPSwkR7bXL{2i?}6j};1T z#9}4t8n>{-kJ8!NETu(c*)GAj41q-aZ zWax9k58o?MOfjb8k(M$=OY2$i?&0geT!-nyEH*Db zhXrH-k(rqqoS7fg8}Q!o7FAln&k(AIifB51!$xc>KRTf(MQX}89(v;7c&DpFF z&Q6Ia_vGtMvY(z@cJhVDL55UAtsOR?Tymrm_H8w%T*83~++2#UXxn`BN?*@Q)d>1B znY+?JlJtXxzX=aSHY5Dr^uoejkJD{ZS{6TIeAzN7D7!Js=<538^Z2_(oJnbDo8m}D zL_7csM?t?ps7P-X$l%sjT}%tk(TkyZP%4Z~m4*r$tMwCA+qFa*uw1mUj8;bM*NZUM z7b4=nr`t(s1~JeBUnIvQaDZQ zfS7nELCe7IkJWkEk^R2t_jdSiHTGZawl@>@V$<>}u_I#jUX6r!f!M{~0H+GATf$NhX0%1@aBJ$O2`kt11rQVG!%if5CvR$yWqcN3Yij zymaiZMVXsOxD@Whhq@qHqAu8e1$6V{>~29am2CLo2dMe*r_AY_j4{?vnwCzHDgd%# zk;O47WZG`j+vw8+`@`mMaG76cr*p%_qDoMIY*{{Uxe^Av3d&QT>~VXVywOS7BJJ7b zplVapo$-*m1JFv2F$a0j;y$yb;n7=t#&vE(M_G_ntQf^dngGx!0E9E70r43hEA6wN zMB0{!M<9LYU;+Og<0wq8K~AcA(-6{{iKdYqXJ~OS<EmO=<- zVIEHSlaLUgbGWoIu+v$v2OChJXr*YeoI_Z-MDw6KJy%Z`} zds>v^Twz9Z>9zyhVvPmDqcZm5r!vl|TfX;6>=doGj?I=iK)S<$bugk;AYwf)AD~eL zWa==CrA4t0DuP0pEZG<4siy+l0AALD;SoZe97i^_NXw-pO+DqK2qwgPKos^6gV~ zj7!VCRx-nqZnY`dy0v^5(Jq@{`VPrj2R)%`7uVLxglU9_l(3ny&tg5i_F>jhYXR5< z^Tl*a6>StK90P@(>zZSsTvH6GY#+j z_8-{FZVw*-16Cxqq0C7Qw);uQ<((xG^Lm}tejY;~{TE1ly}m^Bw*^`#rQ=_Qb3HE9 z8bZ!ux)$N}l59Z6dbvU(|I|q|VP`EfPU9h&Esaq@Gg9!s$o2xhLHYE^`dCaYJ(RLS z#M(R_jOC>CP{%j^=*F4}DAGtw<{u^*Jlhot@L5kQYDVc#kqQbNCUS0R zg~quWM|6g0g&Ccn#9md6Dh-e5RS#d4eDrL4Y-an@m8|Rn2FTTWLh%&GMzT8eXP=%y zCMuojf7JN24lnrkt&P5!V+wB*+GKML2D!jjJEG@`I0UbG$CUM82ZYn|EPkQ;b z8{Tl@wLgkwUrby)dsG{htu-?(7;TSFoY$uVe8gQs4U!go-dnwtJZ)80g2JtwmmA%qFNPBwrwl1#xX&+0mdGGNB z_hR88F&jH_w|5j7cl*J;dim=IsPMnKKuhO|1&5DX*9{y1K#Ldv0Q8?OF#0D7%(pdd z>^9jDe((r>_vc~LlUQT3U4|6cv9dVg&YB2)S8&M-W#sqbeQiZkK^#``Hm0x$dQa~cd zTQi25izj5Uca(hPaXTX!xI`4fYbU%WFXzj#T`(XAL0k4fe4%xq%tocZuy)51>&_EF zkrW+$w%c@teSRD%HDE>EEWhkMP5lkJRq+YRw*m!U2g2%5hwpuBl_Q=}n{=W!7;;+e zMwj%;l)XddV4mfAl$+?1ww!4-r_+%a4LGr4bi5Gc8Um)00=#A%%gxV_O)Y;>KyX9=5oAx1-yRKx zSeZLFu1eGQP-lv;hA9r3WE6YKGvzZwW(E3?m(UrguUd~?+|S*eE>eF}3JWW#n;tRO(HpWi5NWF`STGk8IvafD*sn5PpfMhBACJ1`aU>@R?x=C({J98S?I>b6Y% zvq+jaaI`W3-*&73yb|6|wu~kAO2zFzh}gR>!M{?y2Y^UecHC`q;90AvpeM`OZ(LeV zu^lj99vNS~VULsaDZFKba&dd$?;1yE3Rz}V*I-8uxk4lJ-P7Ds(&S~ri?RXG-$kM2} z4;7$1-okpTXhRFu`==?Q@T7TqRpVKVwU{e@|<4t#%kL9`OC-9PrDx{&Uc+_TThmO)+`kH8r~k6+b7H`f8XKb zqmu@gCSO&S{m+>+UcQJp0d|QrA56o0vSirnK>UxE)~&xY*f>TSi~Vvnob$Q*Cm_~g zqZTA(%8CX_%2pTID^u1hFwIgPc(2W%JlL*f@L1ttsqyssgT*NBW6IT@&&h0Yp*--V zK~xVmsU!@^hMFNtW$-R_Y@w4C(2jY`5uEvHw;{rL>PBf-!-L1Pk^GOEKJoH2=l%oTPg;QM zd^+vf8uA*1Y6d!LyUqiVn~m6`m!;fit?M=tC98(0aRwMI;hT{@^bi!HaZOBSBrVwt zC)ZHTuAPA#bsD-3TL~4~c^8=)cP?CpWVTQ=2{p+Gx}Nl=XIXDce9dk2vkfs7m}Qn( zG5!IfMqQDAa*2|f$Xd-}OjOo`PzaM?5sbQpiyT0M{h$72uFD{Xtw@okbH-eHEr?f9 zY0p`H(GC6?(HnmVBcHDG_F;$=RS|0qI*Po7-HdcKn+m8V?V6P}(P&Nw;H-y+wjS&c z?>~w?mU|j;mqw31WG3DSdCTQ*<9r&mNF{fsr(1?M?ln>apMNr<(1KZJi=x`V5=2#8 z4dPVoi*To@)H)nit+7GtF|M7Es}HoHxEE<3C5aSm^83u66_G-1e9DLU=4VEksuobo z%*^y!M@nLyNZ~_L#w@wBG)VB>hbynI{v_1nYlqcF*_MNBLN;)mr&dF?GadIo-Uvs3 zJYmLQg+tX}StN@_`JvxYejE9perpK0tp!ZsJ$(e-H2u=-@&A|13dJ(azz5v9*}wn* z-KhWL*!?53puNRE$4-6QZb<;fFR%G`00>WPC5{0SkBzIMI7WqHd)fA|K_> z$Jvb%W%zg2hr~i{bWQzFfJ&93a^7{*ty!0YW{W091Bz8#@psQRFMySWgegQQ8Oy3L zqEV9XQ`BL|BFE!Y(rnfp1lU2Oq5^bnS$R6ppiz2}F=UYl^T15v9}6_FS%@AoHQ%6# zF0nw7hB?Z>b%^qGla3e7j5I6NPsap}$G;WKloX>KBA}WmnzMm{A`%4sHB%v`Poauky4lV7t*Q3yNv-J>YzAu)6d5TLSjifsF$%;tmY$Q6vC zVBIsEg9ZxhYIluW9>Gqf)uL6;)%f^=E}73AEeIUX`1meXrZ%{YV^l-AQc5F-aZ;n;iQ_FEf&;mXH=T-5Tu ztnw>e+kq{O1h&`Vf3Ye|RyWC1jF$1pY1gw8mS_B2-J7~s?yvR4$3Pryh1|z~mu=wl zKtbjTwq56aJSm{?#lga%SOeIOZ9Hb&o5^M_=e8V4N$g^P@* zU>2tY&OrxVru~Bcb?P`nBU~5mTea6$=ONO@ct6Yv-_&HLE*S5CEDdf&32m*CXO5{$ zHYM$S5NWh*RN@QB*K~fAENWocYK@v&qAiLdDTJriV%Fnm+@bi}T|wWrE0*e#P+XBu zHsmvB&nfogw@RHl_H%0eQIfTK9kZXj8wP6FYu09mZ?U@X0;y!49AoNZs$;>U%7D}; zezyFDlLP`UW!6nSoA3<7yb5t1SbBz2&-7|z_UF=xvL)wLsmB0ajyU`y2(LeNSNi() z8|44L!Tp0cOk)3L>rb-(y}|$2b6?TalE>ym@fAPd$7uj1B@B?suR?b#=O*_&=~&P+dJz{*HP_X-XMUmx!W-JjWgt1vUrY&t)|Pt#?HnLfKkGi zsh@9TE@rUXa+m8tjRw9%FpS*5W1Z(3yEoWFOa`J%j&tY_;*SH3S1&I%EJEmj+c`|& zmDrEUbi0tlq5oFFHb_ChZw>QAz_1;G9s+b6;p27R5qrt_aHXWyYh_6N-~doSt(YwY zK)ebL0@u|j(pqFML;jA@YID?23ORa$!ToweyV=hkBQ{KSaI`NAF4y1}XTy`iGOG|S z7`v}_bsNy2wi_fE{)M2W5Y$HuE?lHrvitmcaYX+X01{0k+{4`#OOR^%9H3bKc>Vdz z|BCHWz8d$2PT)BP8E{hse#=oZc^T~^b_suw?rLnXR_Mm*HrR8ImbK$oGC(;H?eOw&kZuYCmGxkwap zw-8?@$b^vPtGNJK!VKw@Thtt+G+|c|1ey9m<0!GF!!vL{2fjXF`V|RPzpD zE70M~P(3<&3|}KwWO5bDSh?Rk|MiTG-&7?HFwpadCn&y*WA=94{nv_sTv zR8vxd<BG{}K&owteJl_n5$4UjU z`;1U_0pe^7{IFpIJ;}pY*}ep1sBNx=Bk-32+=$*Bj?4Ue6{*r{l8f9Dy;yxM$~xLy zVzdxsQGt8P1&0hWTqU_W0gJS?z9dxSC}>vCi(rm$UhlQxj#K`?-OfZR36X3{vWt8H zKe2#0HdD?T38E0p2wK+DmyEvA;ZZ77%=)GxTvZhilM6u?EkLTJ$nx5(S!K8~`&6zFV2p=6e5r&?yPpiq>l1sX|&_(iSY(@f_fX^QfEw*ZPh`W9yUex^D^`t9#czrFkk#dWU8` zj%l{g#0on;1EA8UWn_F_$^&GWnc7;l%X5y*Wt%b*V^+_TeNp03iiHc>Ld(x8rC4eO z{B!p;b&b9F9C|HgY`@JFkdGh>h1oqpUG7XZdt`R z8_q>UEkBV-Rjvy_g!HiPiY&eN=-p>efFn0L)F;Gf)Z=W>IYA1DdVEv-S2=aS0-PvC zycB(_%|K%JjY`v(RP^2}n%DZI7=racAsyh>nm4$Qt{F)rOQo9>2YuMaA;h%nfwJnF zQaBnLt>Z#ump3NVMJDZJ<{tz*znufCgF3nUCw{m%H`;kM(WgBy2PtUhJh6C!W^Gd# zZq4NCK|v$Z?VXLzrRd7i`7+ZZ$$b=0#x0bodu^re($1b_HE4M>a#fdWyP9&HGR~pG zlFH+*T=8sfjp~O%7pP|70E&J#IG{I1(6R3pIjIv|eZ{@$+2u#&(4W)fYSo7Zr_Y|0 z@6xQQ_*#og&C0x%LEtBF)`}DnaRug+!Dyaob)diFLs-)Na1ZrCr21hVYX$zK`Dx*6 z>6C^=62qfHh}fb;Y-o{d6i5vX3d3Rv;V~gZY>^_?G=v8nUTD0DV-L3kV-CXU41S9~ z1UVqTb)Am916!i97EUgzAS{joMx6S@;MO$YJmY}ysla$A{+!#C-@J7fyPloj%x_yk zJMW_C`Xj%8n>z0C|I1p@#6%WdR2VCwf2@7L0RZ?HbN|Q35_PvXur;PLn$ghu=Vqb! z!pHyGZ@|{%ti|f&1E)#@u0{abRVb5Kz9N8t5-%~DX&{MAMl87Y`JBclS7+gtJvKrz zS|{+R7$KK zDukHoP^Vmi6E={yczWWd`4b6>He~u64wGP95+00(tA^PuH2cxwAy40z$mc8sB?j!`P(TseJbh|``mZ_u_Y(I|O?$iC6O zaCTd;-!1uON%S5$31*sC=7ARpkGr=qlH=LP+Ry(S@5y3sTnm4L!?a{W_Ltl>owT&& zocga+6C`ZrJ2}zD486A^&t6AFm+|5@G78O%QZp!U`n3n z*;xvJ$HoX6la{`HK3}%I4Yo!S>>}(hKAl2+{_qdJ3qaw{a|9RAQ5*T}5o2HFBl0gR z?tp+9oltH0N@Z%MvPPzI1S}9UM2mIjBD?{rI_+BxNFNxZIV~FJL+znCvGk@$m8XCF zCA*5S7&f`0l)6k*dL4WWr)`y&Px`AR!VXh!PzgCy8~teP3oNrsNav9oFo#V*E_f9a zj{L}gCk}lL2MixiF9=geq-YWw7DtfCU@D~ujM zsHsjzBKCz1;O3(QAH zA!gXFkhiirG9yxA7UPZhXI>(*C}W6@I)i>02w|*4*+Q&oq%`jMhB@jVHshDE$eEK- zlEfwE$K(mP_$c$Ef&o@$PRW*8Y(F8ZhYayjp5{@r)kII({dP$mM&WoZGv#%!J}K`EeZm&{_H)>AGzbIV>mAJWr&?* ziC=4?sKjbc+az`XdNK~u0%g@c>>>^%5Vfr|O7~I&S5T>>T8~Sy&VL_y92#SY4@`4u zDr8f#kiCdw{`R`x6M+}7t+Sqjzf5>I=e6#ep7OgkHAQ4GUqjCof-OK;+Cf@(BRk#H z4LH?bg`d@!lBb=nQ#v0#xQH$mLqFKoL~c2sPhL%YFy8Mg1-X?Ya>mlEE=z-?EeA#0 zZ4qdr1hi!Ecqt%C+pDyfV?rbv7DuEiZ$^5ZGt#p>lGcH(O@{$+)&!)j0zTO z17lh$9xEm)jyy|~s|V~wG+%Jj?agg~6U+|!S@p!VXco2u8FgMe(?g+Z7><nH#)0lMm$;Q|v0&5Gmc)$R#$c-HMPAW?KeL z!_#1nU~6H5KDU-#Xi%Z1j?7ywQ)-MXqBEw?ubC>R6mEE7)hV024d(! z$8Z=YA3g-M@pC*=NA+vYiy?tgGfyjGYTTf-SU7!uH7(1OChB?wZsevs7i&zzYfYfy ziC&Q;`LY=Bs58mrM6yLc6Pu>p0LppLg0R31InLD#5vq9yjmqpm7Lfp#g*Y>>j=LH~ zdgsz|Ge!bQtgTz%37V`QO$o^5ogq=<4yhvAgs)DEGJ|ZA_ak`3V?%J+chX?azUZ*Z ze%A6f8RV;piW^QJiHZ?9Z7EQNdnDTO7D<>*MLDnjW4!W0HiiJRc=bKf*VqNu+KIoZ zdn&o9wf=&$`H~%&mxJo7n=0~@b^tmgP0Mi(l+t(}ugv9T3_}18bEr`RQF$RN3^zX|4=Gv`!5yh(Xg>Q5c`)3QT`fu_DGQ&Kos}*LhQ?B z1LD#mph#3kikTbH*GKL)>pB&bectA17#-djI#G^Mk+{2_WTfTf;M&p6&c&qGzrX+D zl#!Q_0|YM{!GYrtGppFBrI^AmZ0RFX+=w(4eUKkQaqXz2BhYBG9tJ@8cc4vopdcGC zk@BFINfbAOoH0K}$P#}o@B;((wAobLqBJ->-d#h@9PJ=~d zu_b8|gmYdNWO^VyVXWAk2&sWEJB@CW-v(f?EEyA7BU)f>W8Otfk=s6wAQcUugdJmS zJ81+;RcHqW7%DkH?+oA=u;lr;R|U+%Gt)s_nlU=i@&(+lwPVL__UyksxhFNVCjO=qMq~1w2!BcKv|5TGu&+HUiIN8=J+AFeC;v$MH z8;#WK_0_m#4V_%?tugY%`sG~&wE_0 zfr@ySMen2v5QM2->Mu5iz9VBWs4b(WXEGsr=80NONwgqA zx9E?jz!M$;rclWTQ{MD4c14|h+kTNT%_HpvpG;C;G6;Oee3g;X(wjivV89cM^Q$QJ zaeGIn1&xc6aOz5cwKvkD2jJQK;PWSR`?7=rh-2gz3g_LEBDNS`W^ONd95*>=AHtQV z>o=h5ytP*oWtOdEKdfCsn%jzO{?rL$Q6mQ1uY7j4>y)AcJJ9RR8o`y~0seg`Mm?ml z89OUNbs_^LwV`@GOLE-lJD%25aRV0zH!b^#2+*)hd&Ho^gaO_Ub`1?nj;Y|Vc{K2! z7@aDb3ggL@VuN3wBq=kVG$~AuNf%;AP)7F(2?qa)A7uNuHfW(p%xafvhPP0zZ4p@a zQuKnScXLU00ZAjFG&_+gGiJ-Yu{P|6W$}ax7j9R!Azgd{5JUcy8HZ)|AwmKRfkA&Q zX?RPf!oY|SfMj0FfkJ^GPF}H&?Tl%m2rC;{$J6$i&2>}{Rho8EuOA!r%oNm6GOx2_ABjS};zVvJitMO65jx;>Z$JtF%t-mOzBZ9Ui~0!Fnbq zPzc=L8Ffz5<;XEevKiB&31{9Ioz`p_Y%Z#Zu<~e(un3O>y^By7-j1R4Yh7^vLe3D0 z&Hq)>*n0eG|S6z0QkK^U3*1A)s4Xpby zZ(9ql>k8?kciN`v9j%!vvA|yf(-pj}U8=w{si23qVH16&=<#W@-P#c-TDN@N7dK}YS)7dVO=QU?MZ!%ZRypW1eXLX0iCj?q+2%T8rc9$Fd z=9&y@yZsEKsj6*I6m(m@F75pW%2&5ysdB;?NQ!J(hv)1!_{_W18cJV!-dc#zcW(hl zQ@kSLd;@8}_Of=FvNeQZua4U9DJBe2BS_Ik5Af##I?iWG-m_)UhRf zq3syj{=-0vEHz4tSruAwQbaE-(TR8xd94fqVUl;dkKVP!21&uk&1D=%LMQxOW`0cF z*)G&BZh=wE4gK@zODQ&UMb=!;Z@Y}eay0goHw05)gjP$6KB$*qZBujTLVaIe@X9Cy5SP#>xG*$I(GIqq}QvuiHQG#iHi4)d%Z zPJbJA;ef2rpP+pf8K^nr<9Pk>x3I$lw^e0N-jOJL=lUjqLyVppxQ6l=Ya=GRtZaM{Ux10#;V)K~Sl+-%^jZL^K2 z-RbvDIhd&kGY*{&+-krEvN7Sq(utd!^LVXWgU%+2E-jbTwWayXz8pwIZ{fZa3A1SD z7WcFB`Euc0$4RyxN|D7?qF(T!q@zq-yRCX3wwZf-C!hUh8%7MDYPB;dfV2k*PSXdl zVwHER$8W{bO;Bf@+;!gANmhmx8R1*m6>{Zqk#AA#WRzra=3I_Ery-f_z+mik;aDbu z0?UwEzra?L+m=Lz%?cd?)_6`mbeK7wf<_-nSj|0xr_gfK#JV z6=)_U+nek?8%u$KsHx9>PRU7@nj@J0fDP`^D|gjVZjat&Tp+6h#<^tFCO$HO-cVD& z`>4;b-#+MPB?K!LJ5#qY@Q3bFRI3}8UNHr-HJssZ$Y9)1MyrtZNhj+2`78kj5fS8aj?Ox_HlWZDvpm#{ywyPd@tj-o)R2ltl zV|GAo6VkBEi$hPp9w`MOfwV@VY=ZV<+fCv^a6)Bqrvx-o)m$kddw1HNgMPz;9cu{r zWNGyG{p$Am7EnUYsjm6H;@wL|1FeNs!&sh4szm4XSh>)yaPs{2183Bia6Cr_A56ACi4R)m)|cTr*>fAezLhVhO>5 zouvPmLkHh_#04YBQx!N5gu&=*qoZ^{)}0a(CE=7Y&*G;littP95c^{3Gk7c<0&1ek zGpxH{^P*XwP=cl$TKsO#MxbET;z0gXl5fIDxjQZ8jx6T#Ez0oJeiv@%DKIQfQBa$ z+v$Amu{=my)uLRP>&~Nm=q|ztn0XA#$cZ)|aH4BNST<%>LWWJ7R_p`!;?v8|az@tN zx%zaztpDCFKdw*sw3G~2>Qmq#Dv>~ekNv>5HGPJlKB=B4Te(7<=k>}F3E zKX+)3UrSZ@)xf<$o1W|!ug)yUkJ2x-o9Ku;T~0o%Mf;M>x#<~p+n&mV6)*|Y?6;&q zZHnR&6W21znW~7}0Oyd>KvN8t;wFZ?Fm|W7^r8&wJCnzOLgf7l@F}bri>kP0#qOpI- zN2S_$X=^~^C^fp&d+VmnZco&5E>Sk+hZM~t+8Bj#G({~aXaqKj2u&N6D{LOPz&}vm zXuzfn1|Or=PUs2LA*N>#8b)RK@vmQC&|og##cEszG-1-4ZivjukP&A~Kj!jsIO%&( zgR}X%A92Z$P4Qy&-%XcJq6~wD8+yH&;>p5}``nJu=S-;t9q7vJGbha&q8l;FS1*h% zrVNSCW8_xZ)i^ixBQu9J`ljjXURaJUsB*1>(&)>Yr;k6UO!CE)<&b^jKnlh>P<3HX2Bz%9g?G$#>4NU4FI7Squj?7nKsEUKGxHsGJl(9AiIieD?`rp zG-^c8|H^D$A0--5wXVUAx9%UJ+fCekV_%G`wB@!K8mLgSX_kP=kpAI}qZfl8<*T`! zOxy~W@`Lxd_<0!4>)`S`p2_INOAld;9vkjZl~b_gyQ_hmo*v+`J<@r$`!3d0HRZ3k zm8GQhV;Pz=Pq`=+V=O6IF@lz1BUoW*u?(W@t5q9#vcz-~3N&bkoiBEgAZ8rHtTNFj zo31n?s}7z-lB+Zo)b92CH>ysQ+K!b}p$(m>7^S4wrP_NS#&ghvVl1tnNOg#hisWWx ziU~=#m*1z&Qtyg^aV8qhHFT z+Ju&TOdkJgGlcaqeaZ&m-D*CVRzO!&TFmKo(w5U2xl((nr_@|f>4C83MsPgcY z5b05MF@5&bf@>-4DwVeEyfTbI4tjkJe3%AFg)6Z?lDte}Hh<(7-bCNPE%_}ry|GchPHyxcV%iZY7orCr7v9m+JY`TB< zWW?hep1Bg|8H4APMfYRLcxO$4>K+T$DyU=PE=bmfTAuH|H%3(HhJ1!C#Alnep&_;) z5cvuZU~Wtdczo{_eA2;IH+>pTe%MI#j@9&0mf~+^^4bM?(%Ecy(kU=d;{C)#`>wq< zA8jxguIz8yxED9SJ(`u=8+H~34sgR=iB;KL=tjfEGe!G?@}pqNjoW(?VNbeC`BgCX zyQTlHTv7a2!dib&jk^42f*HyJ06_hZT#+?#G&A{!e(g*7O$mfw-HP9#ryG@fiT={p zc&tDXN{KDN8ck2V!m}eTY<12CC*OES%HPkKn~!T9FJy0=<^}=C7f)B$leVV5b?`1N zEpc*Zq1GD@UcZ+wOn@Y316jyD*7~Bm>^C*zF}%n!e7m4{nUTkV{j8!@`x6~S>_9E{ zZZbgFen)Y8VQ;R|R#c_A5%H^(9QA&$Dc5Rh#i6~pn{;)+ZyrK_)_`kSGewG>%m_zr zi=J9`qk|09Tc0_yqH%HrPX?0@L5|n-Z~{s{jF8n__%AFRIU4j?3ws+qF-&ZE{ji~_B{y{Zf)^>0mf|Jh=G&vC5kxD@)`z2~ zgXZ3Z>oz;9OA<#Lust+S--0-YVXze6=TwkZd9%VPZC#^%jSbAx+}pdr5>uyjXOY-3 zBf~I2m_$C=@qLmzkzY&92XVzW^iNm==!4sC(KIJJyP#dpHtiqhzX9I+n7)jaZ8B@# zKh}VSHh@uzYzpkbj{|l?1671i1`P~1T#>t7x$X@F&%lren=%Mp`!i1LTg-;r@c=Fn zeHpkMMaozwlk;#Kp3$|sKXp!4)rzu z{_H2ayjz{#&=$Ka=b)71M!{La!;DEQb5sudP{ z8Lf|kpANb7dZ&9bwzg2}Xqe7o7~kvwMEAwu`CpVJ-&S8-AA}t5I}K^g3itfs_C+f- zZ%#}>clVMQ9(3B@oL&D;WEhR$IlrPp@Xjk$-I`Svwphlq1 z3EtO626Mt??sZU-sB-{Zy>YrPd&=x`nwG3b6@m^&$<;D)Kpkqq1+h*#cIssK8Q-{s z$_Uf`O9q?dY0Ah2V}^#E8F?78V$LA6>4ObFr1!iFj!XK4*l`SGd&A#zu4Cvu&K#lmRiIVPW93gh7{@W&Xs( zx|_pwtXI_~LB2d!6Db!FHPsgK&P2YjP;Dfs7AMl8Cr5{g74W0dbobyAzvN?dVs(=T zIrsG%ozyv5N8V*jYhLsdLJ}nMPX$oFwqx`qZyrm;McP+|Wn!6<%18PFuM3PYdOUgA}9jZ{tY8C}G{xGZ9WMfDVLRsN0G#{T=sf4LZn0^~70#&<(* zOdu!_Vnwnpono@Z8>sTSVAk>~XL;$gWM~=s>Rx;y(YP$-X}QZxI%1BTpYy#e_&P`b z8|3VkQ`?&DEs@hHr@1O=Rn;z;!2CEdZAc9TM8j!cFZUauUZiEpVj9*x*byd$Jk7M7 zxM-mj8DLAL5`Ks?ZQ&ksGXOYBZY{=;=}YE|lbFt$vjst8Z4HgRX>P=*2GN=+Rl(=4b_{XGnxZ-%dhP$zHVc?skGcE=zD{YEe(cR%F${_<(_3Z<-pp9Nsm$h&; zP!8W5>2L4JwQTqIN}Kc+{zyF44DL_gag{NJZcKG5sG1X0$lV+s6C@p*gM{eKgNQ7f z_jzNhA%QMm*g|gIq>o9H6D$p{(I5CV?^#5)`dypKaG@d1;OThSpvy?5&&2>+(18u7 zn1+y-f?2j1$w=$qBpN%~vC0ePNY)&^rT72)u?wHAoABn%_J8*h`TX%c^mFNW@%0ZJA!+bfP(?*d^ETvzIoW?%4|a z`_(hO%R1AHm7*s1(I$PiuEchk9@yD5kI?aS8xHW`k!L8ojQSFD3gHf-T2Xd0UW(Jp zxz@P1zuR~SZ@mKMGB`f$+zx7W(V<4<32~U8*zLJ)%hmc(e8Da^(`nSu_xhRWLKR^( zHKq8+{OEv1FB7Y1L_DS$8hSQ@0vfH|7%vN`#wbSYI3sC|+~-{vdt}3Wi|*dBwM3*9 zokA;Gqy%R*tB9EfFl*2N{UHR*nnpURsJ2_Be>P3Q*$}3ZM>Ew~(|5c6qUehNJ05bs zyB6EMcV1P=$JbP1EuqeMk})+L+%KaX|!v&#?UeA?lohMTZt3 zdu-dbZQHhO+qP}nwr$(E$2RZ5+&44zUMiK3q>`Vcvb(x_udNd9uSR}6idXqQApWrn z#`gsfE`;L3y$hjCIyo)!yop&{eUH3FQv6tB#PukO7jY!bKXh%T96WEGR5&)< zC^yQZwQZ-hhF7%mOcf*L1& zftRRtn2{26HW@EniO!c5C%1~1zqKo+xv=5{0rItfOv0Q%V>}Kr|LT*!VJN$2dm5?G zSC`e&E%A(?@1s{J^P6=zOvYokvNihplMmpd?dvB}7yQ~R4ewIT-vM+&7uGzc5WPj@GyuPcJqXaa`^mK?AFKe?2I_DF%lfQp`jpC~zReIXw-{9Wz z?e_kBe0hMh{F+Ep6Is@cxx3$ez>9+s^L&4NH+>>d=kI%Y85Tt<`l>}xE3#{@{Sgo`r?}%rpa;^HM%tQ(YRWSz>67Y0deI`zLdSN z%PH3xRHJ$3B$9#%853aeK?OPg2L8E|wcrQ^6qQT}X(6}&RZMVYQ<(1oMlbn&Uo_{V zupxh(aGCHYx_y=qahouJ(4Uuthk9;IokgESgr&2Ddt+y70HyiuG=Z(>I#DgJqWV|a z%}rB10WT{S_kefSyQcXRaC3vGr@E8n-#~qE&RY~%s>8}Qy0N+|fd`sqKotvnq75OC zjIJWc&^49uFfjOfW&I6WqsWM$UNlppSL^Aq7!6mev)9}jd`D%O?qt+FR&){+QxfXK z#_X3VPE66|BcR)<4+@EHBHa{MoDGi0O0{+ieozGNm1_Aa~q=Tk*X)y9Di0;WK#_w2*hSE116=ku!Mp&w}J8` zTx+*cB*yZ`E87%AkUKb&WB@~0_T%dIBn7s;^8-@IVyWXm;_( z2xyJh>?jXdQn4!`iEW%PV7-b@6Zb^Cov6&88k}*<5u#Id(i#!PfC3`_kW3aBh zM+V+C8-8&X8tY62|LfsOnH)I7k1bAbU8RmRt7r{QypkxTLdioHF!0D-T-+VtugsQ{ z(60`Nql!+Vi_B7p<2K}Hm^?`tXy@c=Sg^eC`GjFYALZbhIfs2{IB6xiJ0e}t*&a%avMqbIJ8D%HwMmm~&C`9%!$ng#Cfl;OeMPTf-Wrd;$B!cpGS|Bnq<${a0nGCoyuxE|b!Z*RReki_G zNW^q2o9Q$h3wjJTuKAtb`gD$mmuERr`DR62GQBuIS(dBE1}u=*&$Q$8ZhswXb>e;v z5av=18|P(30N*>6kObt6F)PShV2-lvQVE*~MlN?XB3hnxN+7#2T?(ToN(rXZ7Gz6P zTjZN7l2@Xx5=d}wJ49oPaxK$dm8LbsY7R(gw_w7#53|V;iW9Iu{x=Y_qPe+PYZoCC zTvw)~F#IZ*q5kf7;+c4gIbnh`Xj(%Agl8)5i9hVdsrrAOd&rb5C+4Ms3qpaHJ_mL_ zyOJ~`rWGZL+yoK@)WEZ@hcOE@H=uB*Zs+#(s;v{5u~H6t}s`0^q<42rF1a*Xnz zXJ}45)fIzJq4jb1u2hXl+Rfq}nbqAxWPh_K|tL^GniDSX-O0y0aMj2M-7` zziBnwUU<(Yx8r`!x03?ck?-Y2)6I1Y>(!~#aJkNXIu$LS7tmk0xH)nBYm&*um8F8| z8+p+%);lBIEzp~28wBL!px`T$wd~rM;LH{U$pqo_fMlQ#NGDWy-+@Fe=K0BJ>kbIM zr0HiHRyQY|`~eYjW$9Lkrtdsagk#wrNgQz3A`h$PZc10*Ai<6e*a7^dLWh$Dw5_~} z7E`em)uSwGt*aZdL-=49M4Ne>ML$CRB>#9UH8ez4%|Y9d2ik!ykc8aE!n&2fd&t)( z3Eq$oR_k?M_``y|xwGx#*pmS}MfQ-c&i4>$#LtJR#TOHn;kxToQtd24C8=}Vn^ra2 zhnbi5H#q0zJxN;kBn)CemPJlwyNf<$U)ubMp!h&0skOB#IPw^y)Jmd?aC&u>@q43? znxa)l-Hobg3K5Trt#<875Od2Ocz73?{AhlQ#n!c0nlix1pGX?UG}=fg>VT)r^*O(Z z$d@^F((d*l3c^w!2udo+#DJmQhUPLR8KRn1nAE zOkLPc@4P%=39&H>$kf5t6o8|8de1P4{tnIYvmF*a}m@ z&?pneb84wbd6X`Ubvv48`P2y9kY|+!_O|(?@6*UFZgIFHhwOAP-XimIpz(OhkkwRf zzI=u`3ISv{cG+g^?Z;@2(D+pRX2YUcehmrzi{DJ-&w!Ve+TM~u2noOeAqdmj8|;E+ zUDN*hauQt0VINcjA{g$NCCAN6?Ly>@UK*DCbNR-gpA|$BlSUo_0V$c32v+zdEBsjU zkSbJK4*zNSO$wlXipa+Z0XA8Agjq_bsEIIax=ohS2wSN>;mi%qf@^QEs1qY8qsXieak@@=_4OK-dhlz8FbY652`J(^8cL35kCb(jnI%p-` zs*x@7vX_6efzGPdi$r~Sr}}(8@^3lcM-iv7SwHOXz=s|FNLePY>%#!$i)m6+6mBV} zq+uH^H@SJqDhOs?IYe;$LLQ~UVvoK}f0Qss0=p>KoUqS*|g?f;jX2yeV8kzItZPZ2-h)g8n_BNZ81Fpqmf;9R1mKhg1@1ur^xAu8ig=TTi zkYK_#Gyb)|`rmrCPcDRR-}uNI_zqhCQ7w3!H!g38DzsZuT#v^o^~&?WuE&$*7`Q2E ze~asW^QlQ7w6ems`FlnocWkrFF%;u|f^MpI1tvgql3@ONg-(e_Y$|G#yG0eK=EtGCWtBVoq+225*)m3h%{$mim`-@J13Av{w>(B}y?@Z+=08nj z`JPXN^?6$o@Xg3)6|(4pX@(r==)I9{?j%C7wBmhUCg`P?7OCo34Zrq@km{*UD65|H76`7g8In0u#`n#@qnG z7GBT#9@z8h2brf1r|h&Z&(C*ptH2Fj@mjrg?u*Pdyau1K5vsJ)AD2DLwcFO9_O1wHsIQ(ViZ$>YV)IX%0#zJcn_g1tm|)tiRN?HN)SP7k zw0%(0KB4qamtU9neoQIkd^We8Bv)Os)IzXRhgxfG+PG*R+z=?NWttDzr7l|v^q^8q z$i^#Jf>3h@h(~OKiPNGUX}B*g>Su5)g9K#8vVDLa5h@xP*mZPDw zz-X6VaJ><|7*$b&wdD`XRwJqxmWl#=k2w_!n~eZd`{g}G9xJ(^%%&D*+=(D*0N$t3Hi zv`0P4RT-Oj%#GbneNqPwFCK6yp(w6~1LQth>p0t9dA4DlY-vB*+H$rVrlA43Ot-V- zeN{J%<=2GEZpkvao=7{XBc!VBcWu4G4Td}Oz;0V|o-8>kmIUO>jk#e(cGnp5;7s<{ z8uQ?E_0>&o3CaH^B>PTG@*SJ>$LCxJe|tCh?@#>H?&T%Uq1_My{w4(Uzd^pkb-J8U z(pOW)P5jd-(@&wfNH1J;+(;~OzPWQFF?q(7b#yLra~UqW+x1oF0nto(lh6H4CTHkrI_*8Ay*txB;QrWG2Ojx7d?exY@o*B;<|qE#mk-6i zK>ssbT0Hz&ge3{25dVcw7YzTM+9dB}Xl(P(ayj|eKRNnmx%dbAfV+9a+Kfxq(0Xaq z%mX^f0hP=`XJ6|rvcR@5r9z~U29`W^2>1P+y_c1AYuYvO77X>BATj5_`Qf0qYF@{_ zGv&PTJ!*b5JAoyfxS+^W1e*6`LLaA*bLvXeskmMCraPB`<=Fr6{0hWLQP&iD_a&^O zoacy)hU_e)k!~hI)6^6|PqMK9BX?wqtzSVo`_+)QoN1=#BxOLAoYG`PkE&8SV!Q4U z)g<&rxe7^z%$>nJ5lP9CaylTP#f+3xl%vRes_7siK&4#8VyV9A>|N(^GZKvSo8wn*6D*1y1mi?yM0OEco7_JG zCA|aledm79&io+mo#b#5sltCH$B!sK_uv^&f}OEc0NMazU4pr$yoLUH04Wb>nxkcZN)+!tm& zV3ws5tZzfl%kJ&KNPiN_VALeMq?VI!-sHj8QtSZ0(N~0Y9O*LlBhnbaA^9Wz?AGBk za*+5lAzKTF0Fjwy@{kpGutIp~@PXhdkp>HdNA5V*k?k*LPTEc0+yMYOV?n4gf17LY zaB^rv-(8G6TEvy(Nz`KD+KzDj!}2$k4o@kEkpZzk#b(I&W?bxqmV_vKu~}*41F3HM zBx%>2raO=jUKmtiK%3|=)ZfwbQ`f5DNKoBPt%O@gEOaJY#FrB0cAEG&JVker&CA~g zls?!@nZ(l{KD+7d!Xjo3gl2m0XYt2r`0<*}w0V6y8yzw$(%fM*a9+7wtc$rtvhW|J zkjGH7v}ZMRDC14SY%}Dxj8ZmWveU6D#qO*}MejQETMCxEFSGT4HwGFM(SuOe+U*MA z2~IXieiGt`HrY~K5X#$Vj`C52?@D{?z0Mvr-*^oEh`WiE$e*;j8v3t4R^mf>^Yrq! z|BW7=-LGN+P0h`#2B$Y2c&M$@&SH6R zu;GO8Fv~$9ET3f?t0%_x-L&C%Ah|e$+*1Q}9R{fDA}F4+d@vr8MeE!49H26;d^JG) zcch3o`*Sh^!5MD8WPfZGeP~mQ*?R$_G035=uS$zUiY}2TJDH)0WUV={6}Bxih+^0yD1waj;bar=q4ck6LHSG{3(}?WxpH(!!ISLEvEvS)A3dpjWJUkA!a!{W`SO% z({QdnUM~mibB5H~G_yzgJ96xjU_%46vv=>NMNqIMzsY;&-JS!C^_c!3O*y{2K@_IF z)I@qk9vcK3aDI$vQycS1x1(b%q9!}xLs%oleG7`wLb4y0rBj!~K+#fpYq4WO7V|9t zch&O52t}-CIPHj{QV~UN#IE#PA)-xf@@7dwq|2F!M9z|s^9&PI-vIuI3X{;ps%fc!744-ns(R=`{f%TlDKd`) z*`^s7FOx0uNb?3$$aL@?b@$Pzh%o>J%>c4|7XT8c)3&+8c{M#$Fk}IOlF;>VUN1un zD83CeG?On~$!#RD(yJzTy9KFrp>3W;;%bIJ$Ur-Ho)x%-17IW`Ni70puyebjvEoW- zMAWA(z30!zFRd3Rl%HStm!wX%%fC|et|xj0rPYjm8fvOOh2K_FtuHuEzR`Vo9sfX4 zWorZcA&JjIEOm8sf;!dUt{tCqav=03P`-ur!sh1izZ;l}yVVr@Oltcr10A;!!`!{MEz7&J_`D} z?$YgK!SCYr?*m7=i>Ie#>zaIqDln6thouIwcYD$|AGef~@F!R8)93O+{NL z=+Fp2V?aU=^zW5PiF;j^*|GzU%h=*S#b*q@x=mJG#LJkQa{jL+GtQT|p#*?&9+=~#k(h5X>>n25m5~qY#&}sc14>|cd6S~qSfXd*6h+z z6`uR$ZSI9<9I?t73=9CpkWy-~xMncszNHe{p*&>H|pGP%ndG)`eTgPAZ?jyd0|I zn})41SZQb<&?+8A4mNdCh+i^R)`qzq99MzJ`??4<3{=)5B-{IXP9Pu`_`!`7c zqdV$(pUmFfRB~$Pqa8Gth`jFjcUT?n}ZkU_Nf&ukx$Zw&JzHA>(G>n>6a|uKu@G zRabROUsYFoga2%3`yQN~<@^0aB80eH%kTi@GrOnt#P`^_&+?j=lDj+pk=6Lvyv^>l zbwbhmpo_cf zR^uZ3iWZ^_64e1fWXF*?heS^%$s%1R`9~-2&=5lmgo}K4n=X^X4h3l)J03Jfw*nIN z{LIGv8ss<^U%z`@j{$1F5vZ00=hHa<(EHUfzUQGRk^S|SBc@&M58@B!-`VK3h+ebW z#N?4kBzpm_<9>6%XZzN}{8mb@p99}l7-XJP_cNOFwV0qjo(ac_Ki`q$U^IJ&*>w!eW1=^AM}vb+>zj1H;U3B8(5jo>gY zi8>Vfe^0&cas<|j_y0mL!e5-__Yp`VoUk`dfphb|+9mrjQckcu2af=g!BgggE95qD zJOFMqTClRpL(IUaWx^3E6`;J+IJKpi!Y zdqD&5L8{CLLGlR&Gbt?s&XA=qz#HAkD`-aS0dTlY6m+l4rC9!w_3&@k3Lf>d4vxUp=9thlsm?f@o-0EWvYvavtm zc4$PZ;WJ)SJ#=9<&|~3TZV{>$*8~U{-5XI45S-N%T898*>Juwm;3JpB@HGDiv@JNM z0N^ZSVj#5RfJT}Wv*U2lvC!gqYF5^Hn7dZ5$HKavGeaJT4xA@K5p;F^`Y8XKBWA=U zZAF4Z@eDgnrz^P(SUlqp^JJCKgNW^{1NnfUD7$7ECBiutzfN2vtgREft(%lK_<)+!L9mhd& z`gVxc8@iR}9@w16zWTz(-A!Ax9fOomj-uEEC0)`!KP-~@7Crr!7zUhlbb!)Z#VG21 zbmjcm?lGPsM;6_>g25De8dZdgRc_z|Aj?W^x7 zE|((=6*0xWD`ilaK38bzyy&NN`HHEwQ|eFj(OU}OB;28vai~T=IQ0z^G8~Oom1kjc zh{h(H^!n^l+yQ zUv-EXp`99G7=&%|pVz9F&nB$)$3mi(vk@TtyCv3?m&b(~C=2>`iQO56LK&e80y(#G z0M?Ku(Q8UataRFTO`uUDg&HCXdQ3W$n5a0YP$EO^oXcx@Dc@sUhYKSy+xIi9LJb^r z=wA&^DngX(=Q5ZmZ5E=n+Svq#xQW{&SSj?85>1GI4~aTAdIQm=$Vg!lbzYftL=@U2 z$ev)Ym2N-jC<*CGQ)McWeavyvpZ0Y7nDJEu_;&}C__K}!E;#X63N|8s)GA}_IjE=L zNJJi{`4-Zb5`!v)X|&B?L>?i60O(JAyi~XmBgI&y5JiqVD+33WYZ>j+F~!yZ5q+S3 z0#WUB5T}vJjYAphC3m)Rdf?>!^pYAe48iCo>14-7O-u8rn_{CO??M#4bTllMwso%h zVADp8GV?&QloDEYYyKWr`Iol%+H`9ixKeKHD^&qqh$bt3P#J;yj{^p}u@`e8hP{NkO_8z8SPzUeI7lZsg;9yr8w@bwV>$d&=kUjO3_s;v_lHPK$ zVF?=T%iELf9rAnASQz+iPZw>i_5M}6<8UlP|C!~`leSAn zZJm7nS4wsOy&P+rTZPC@K~>&}eQZQx<#-ILKE@IbC)oRPkAf;-gem_=>K&<(RVzZJ z0&aOpU=dLrdkO)!=`UGk07XeQ{KxDygBS`S5Mdf&>#ygD^w-xcX0zaO1H|D^OrIe_ zlO;PvOyKoh6D%upi6XhAne z#JB+7zTAkeEKK#r#eugW#Yu__5IjnR{txh}PypO&SE}ooRqMB4A~@0Z3pl#_ydqVSuv7P3&uQI@a)S56ipMYN0R|IjR^)Q@+>Qo z?%=?36$Q(wmof}BZPleB{mDIHcbu_2g*8ggjG)r1k#BarIdq^mkNtU6w&eS!?eeR0cNhB8 zQR=e4+^vp|UgacKQQS7MTwbzxZ|ma`2k(d8zlHtm4d3rxOZIUDKSUiEO=-<5PrZpf zTgDYd--STw^%jdipp;g%Q{MR^vffRrz1(AxU1I@Vl~|WronJiGsj;H7_uO`MgND!!AF<9*2=2{CvQ^X*{LWslY6dRzE zeNSGBSWYIxUijPsTD;ZCRe|Tz9k1_^YgZ=+e`TO3zj9IP+V>Tnk+<+R?Sq+jP^gH3 z`Hh*IZM}IGqckRjr2&kD3GLm|P`+*2;8#B0xN?M!sufZ#s;#c9t84o_=bQs+C4yNb zRt7}9h*G5(j17(9l=WF<%D`#N&<^H4(*0sQ_|;`oHS;v+e7Dm`zF97dHDhU477@L+ z$MIS<%aAN0XE^wr`|w^@W@CpkNtU8MMOOPH%%(Z;Oi!P^jNkOZunFSiqEwmU=$U-J zn$SZv*!;8QWZwT?9hLq4Cp={}g~<)tfKXC-O<5BRYtrOBhV=U7> zDgLYixAYOpaeD4`JZ!%y`#h$vuNOL;pTO-nWsO{8 zREqd4aiZ=1bso;GEplJJ$iFWHV%N@4zjEkkpIMtl$1^nx;f_B?2)+DgMB6eNfWHCA z4j_W+B9F@s+7_AgHY*o|g}+Hz$t_F1%I4G@yEoxiA z0O7H>um$5+2-PoI8Mk@x8t+2QosMY-sqrw;&bu5{7i>0^ivd8rK1q?nl-#^OnW`SuRyPct>Ox6^(9V2q00ns)*FukzhQ$+&&#vf`9j3Z zUqDZ7_MIt=%WbWcaRu?TCA%_>e;}QmPWtBOI?SiTMSiiajA>#a}pJA>4{sf z{*wFFSucm01&t}QeZ&{pGjrj~l>-}*{ah{Zp`&u01CSnR+%y7xq=i(l>XL<6z z)BZ#C-K|l5C$>7JAAUm?jy&0>LEZ1UA$murz_1Zf4Bdc1sak=wa*|fyM&gf_t}P#_ zM6xZ#F4foUp1WlC3(Z(1^*sbMgXp45ztXZWMlD;0RtlISwnJ=(n@l{?4;e*}#38=Ty3j$I~jm(l9FYM56ct0YZ2$n;Hd2Uv)!3p4Tg9tp{ z#TjeFb4sdtgF$gi-k_y-c+MjouSmHlj($Y)(G0uE)oBjk0l46{9(xN8RM{KwE+B8k z?0Y5Gx6dU#BumiH}uvIc?}R?Y$G1w%USEEsu)M-w|N#WjAIB}c}P&y=n#3CHue9v8p>9%e#Z*%MWm9dN^oQNTDVLJAo| z3Jr{zafV1T4`_2D@`F;AX>+9Tgjr|vD9%St;6ButT^tJA7thV;E|=b3unSz7sWtju zQh&pX>K>b(XbDtM)cV=xmdWS=VHHi$6}s+oi{ZsKaf@ z&Z&U^e0aw|12$CyY;r=;L@4SCv|XY`5hz2N-gu?7_H$2Z?Q@%U$Impsx{o)n1ye*% z3Jl~Br%879WbdB#C^CL>Cj2)3@W?G8b%rb|#h{LOc?gEVGf@M55-c4d;0PN2Sya)a z?|VRg%VIHckJ<@jR8FN*G?6;)toEn^PcgRcK6W6(j^JzoZ!uu2R83J2{G*ynwkVfu zM(ME$KYsNZ;6H^>ljw=~#K8q+wF_Ph787pfkEyk4iR8_qn-QdLFX<5&374c0YoK~M z3Y*vf|d* ziauTP7-vZ~D@O-~HKnxHmXtFA8Mq2>TxX9TCe@!+;7$7TuG`1<9!rMkJgWztImA-fMIle z4IDTcDY#i@ASpQCvc~=BQRBh7r$+;kD&w@u&J>A^D){R?tEO;=NKv2K#5RtMR-%@s ziQ3#rpelG@OzJl_Y_Aa@g)GGEqhPy9lJ@FoQ`*Fc=O*)m^QwT9lTvibiWHZgE6uCY zi%jog3MqF9V0NGM^;k$szcPNI+#I<7({lC&bL(+r`Ct z@5{gpHc8>g$0?!PE}+`1Jefs?L-3$?P4xgoG51WD^gk0&v%;Q-;C%jXa=>|IlE-po zwy!r^k@eYAgb+O%jm7zqW+~L%(c^bKDSc7o?wmZ{sAC?uqMRm{{a&T4mRO*1VO_o~ z=(dlSs%F%>oUK$!_OWyGU+eYkgVI}vvRFUMd9cx=))6F z9KcjPmEkj_?TgNye~x{zG{iBc0(*bcP1NVNamVn@1P{Q~qm+(%C^KHsJ>Rdv%ayWv zb7jlQ2~Rs|lJ>9Esx1k!9SXArI%-Eal$m*S>p| z4rM*0sSl`oV^CX?<)`kn_#`@+2i*XzO^xRgt+N+w{rV;rl6?$?Hny3-tv7{{HLXQE zSs^RT_ACkPWTV*W(sa{i@LE2>+DZE}>=d4s(`eWm35l8gMqGxXj85zYDgHK4G0Y?? z0nX$>YoNB=`Ycopyg&`4vTZTwT20ZuV~4g=T+T!Kg`h;DW&DE7*c{Q&GANhoZaBL$ z`s43@{LSc3){`W64%%7}MBOV!mqsN6%maP?6JZOxCZInJv?8cgDC14DACS%$mA-3w z8(ofeAr~oWwUi|91?7my--w;*S@O7 z*^KQ>%KJC~LY)E=lR*9;rR{6JT!9Bkr7!8wd`}H26HTD!nDg+4GJx(tXd!o-MQ!kd za2v$aQ8PMMBddRwYUvq;z}w1~MCGpEBM9F9;obz9!)le~90IZBj1cO+W|iYg8|tc` z^3Fr7B>qF{dqy3`FH{1PK`jq<`8U_t3Hd`3Xh#5k-s)pB@#Un_`xjGxZm9zn>5ew7FW0$QeKkO6ry#7w!dlw8k-8S}2A-FUte&llr<<#&78E zg^0wT$+Que=Uej0oP?ba(>vcVu<*|7YN4Gfu{gf`0c+BY6@s@7jeugyUR!VF9gkkB zP$VK+>2i^Tj_T0?i84xU)mMekq={@Imhykmk~WqC{h4IKfKg ziIM4J?Nkan$x;Yr*{F(f;MB1?kowSp!=&S7Ck|PftXLHw#_cET!D)O{9yC9zSN(o2egXbxl0#biv&@pT z^U43i-D%PTn2s%iU=(vI-+A0W|Ht{h}YgZ9O(u(L{0poEUF7N9M^$hird zoKfS$sSQ1g)yEyX@tt*(XCT;$cHp1Zv)!kejmg73y>4QmzPI52M~#)dY=i{&`4qIF z`{JXus6&Vmm+i6Nn z-uL%sIF^adP5{0PB*>C6KI$lotINDdT}&BCmbFlrDMh5oF_)f;TiA2U z6Ha=mP7uU^=jahqo-478(_ef(Ov9swOyeOhzqx%FeOTQL-y^N@QIgbdx*+|!^0{oC zWPWaPUgOrjIez`#-o6@PDtO)nI-dr>jxH3W2!}HuGph5K_8LFb=B7y{z;4#tWKKCG|ayf_q1?qQX{O= zLwGz0dw;l}x!7%k1!mSt$BJxwm{RhoD1wB@GF6($=PZ}j%;5;H$J&mY{^Lxh>(>QC z*5q@1BD@b9PD1<~MempQSC3ETqCTa=d6V2o}X!y3=4hFnUB|8KiWfSXGE$^2TP+ESP422Mi&tmsuXsi zagav&-|viWN(TMq$4{|=E%A>W*$GX^dDa{dLvM*`{hjWxVrhQ@$F(UOddC+P-A=x$ z&X1R_AL_c6ZXETKH-fw{m)&E_0M|Ta0v$pML|(P9Fb7A(XH7t8T()6>O%FB_OvML zCG=$3X7JHMe{R}PbW)5)Lh`p~x8~VE?Q82I?a({5EAk{aI}ZkFAU?oQoq2McHyQ*FDgmxQZvL?I)j}Gy{#Ivk(DnACI#nIyF#C`SJUw6_R;2q zLj{;?JF7Tm7JGx`oHGNuWJl$9Z->H=x6w&){Alq}FtIs**fu{*!4y4b<QJcnB1~^l%>=|C5HT!f;USkTeCYy8?-bB)LQCpcUFAekdEpCJ_>syBZeAeno^_fapJRR z`sjdTEd#V+kB;w#E`49Jij~tG(Z=`0#lyh^z#xH)qKTJA-q+GJstzwv*0MrjrcO!U)gOh++MqQy1SW6x3_>9pTVnV0B1Op&zBq zJOBqJjK)~*{%QzdU#YVc!DohX7g3g=+l*gv9k71kb|8jaX$dfXU!S6U?z;Vc^+US; zZ`L23-FWqyu{SAHs3zHdx_k@9Vw5rzps}Y0mNJoAt zU?}>948--^QRro#r6wK#nRT107`Yt6qXP5^-!?J<5>QEGNz^*PS7cD0wI?S@dHbq@+BU|yo^^+&BYlqVtu_6@38jXUz%9C z)v&*yqRwdnubGLAo)m?cy>N}eB3e*#uP&M-9{;>|oS47s-xudjPQcvtIF|BkxOfZT zvZUjh)(6UlLdP&&`>Naf(1-%EfA7ctSx%%GT)zyM7;y>pPm3lk*>%0lu1i+ATH_>_l_t9i;1Oc$%-_K_H;Jt@>~7c*UcZ6 z7J@fRPot&r)m8kPL3(pw!Cbk-8@q}fMU<^17Ey4G%C|Dd7mIU#?gX1Vq zVMDLQ#KHC^ep*jsLMdXC&8;!&5GO}Z)^wDUFK9z@vVTa-uF+P_DLl6y-H<2Hb(r&( zkkAyPq;!G9%T^CkNtnZa!j4S9ojqMrc)zcI3inGfw&ftY{eE(Hf1;#xiZpz! z)ay82SL|q&-dP5G0eyx#7Z}9vl+Kafplie(i24!&BMAs2@fCrY%J~Kf2NPyz?4 zj`Wyzs>v;PT3sRbJaX%a9n^wShfJ6VbR15bf7d{yZA~;9@7T1o6SNBS)(+_-SP0yD zRrj=B*nWT$FM-@Al|5{Ar(uU+e8pR3MF54nTs>i#TkE(ug4N6(SV;qItufA_)YQ1I zN3i)UBysTF(9T3ICd)EyD?;3`^|+X4VzasT{?VwO9KB<&a$Fh9oRaPho41*FV@pP$ z#15`b`JoYU?#tBnEM49^z1Rm_xU+M0+?Ru10In(kv=OwWjm~3iCZnr=o`=33$ESGA zO?z^wk5+4E)H4P9$6(S`1=1Dot*Zj z=v9$-*nY6xkwc@kGpw=OluVqt56Rr#S zP+`5Bez(-gSy?J|Odr*K^W^n>KOWmY9Irkc-z1XP4<)P5Cs*6RNWX98ifye3krqL< z&va}xf~P=fvZrTBeQYvQKASsRrsy1)TIS7K1xgW%zSVs}u3FFflRTV}I;IcOL%2_N zetVNW%bU(^>9it#BO6xf`h-iBv&cCd?Ij}TPrO@?@6?2gJid1xkal3ZvnhyO6B?oJ z52ZrY&epUg;z)Z-G%tKis%U5LxFKKd-bxhZOJCaq?#o_RLpAD&)x2p(yi|=yA(s5a zU4NNO?H;e&X}x@Of0sn}bougafAdmJQQs|IE(Xe1E~Vovk0I9+uddJGEBgeChjj!b zIQ%v~V*a1D&M`W#;9KLdZQHiZ#)BAq- zt(kMytl2Yr_B;;|D@_Sou5kFUeWbXCSiB~2&XIcYKnd@C>DuLOLbm)u{Yx#2!*qB@=4dVNk3iMv3F|N1XxY`bLs??ugqvH)Iq8*fJPf44!>ij4Ov0 zkag=a{`&>kz8$r8uGIS*M|uCGO%dh;>XaF zkfq$X)+N^E1R{r01Ldc-rw&}}j~3gX@MS|yj`{Bmnebu+M=J8?vE;5P%!j&oCLQdExZI4lv6gLvjeY#mqk%~cj zaf*>@Mu7p`WGFzk(=-^10h~%G!Ht2wm+~SbHB^JAiHaXR2c-K2t>gApJbZ-PLk$eA z2nTyd1u0WIOo6Acw2=(7)DQNrjcOf0I#+m)808$$t~o%D>Zet&o0$nfHdl4aK7$F# zCnoW2N9;SAYmk{X;jIMTbSespaJ;n$`t3HAdRTbRNV?qjEt`zS37@Y<*t1`uWgK2F z?>3%Wd}<_h)eWx@XD(cLfuu)DaKXYYW5Uz6IB<9JFj}mdNxZ~Dn5eHbK_2`g@NCpU z52(-UjIm`(4arkx5Scmd#wqj~JY72dm z5~ij9Hqhu!!bm$Eb{^oATF;~4w10N1j?6|qrrDcrnNRMItZqYh?J$p};_o2V*f$!q zRBR?fWl7Eyta0r#gbcBmq`SB_lmNQkpiNCvBg2RvP(8Px@2Qi%`nmc$C@h^#DPb;4 z7d+^Z4{VBdkvqY?8Q;bv_?X8h?17t6;+uA^WQykr({oCS2^-6i=H&%zSKd+^I0)wL z2vZ^jt>Ts+tirUtj62V!^?1C*9e$EUtY7YRBXFmDSv{&T_rz72_aY+ssX294gv&Jq zndAD|g4Cdvie0sV*xM}xMhFmEdayemrVbKu9y983&vZw za(DmCr8PQLquX1CzkUoZrhX2|{bs`MGjz z1t>!T+%Y**{T!KzV_5`lO3z74JH0!=Km}~IM^MME4Px?J5z!W(cUO*?Bd2xwI<0)q zJ3^h`5O|RUKFq)cbAhd8^q?T~eTl|5+A4@yjx~|mPPkZKa}Ri(h>d<)d)+0eg{~v) z-+Q9ZCS)>>40NHqF7fMx+8{3pT|q< z8ulZk#@^PD$*Sxc6FTw2M-PYkya<(mBn{tb?rwpz=Ki`M_>+n8Ydym=)q>6v!;2Y|I5tq=4$oXoEXx~K&+VrGW$Gew7F1&cuT*` zzP|}%b6|mFl2TUQG%**F)oN93joS_9HuR}{Nuus>`!z?7fT-D+?-9VY#Oz|XjkdlU&^`iSyXo&$vqGQ&+eSLqjN2V z`51;ia}LQ3o0=_z?2)X&0!x06B*OOK3TQ#k35gBo=ca)VNsen6pWzd`XJ-bY5jw*z zmh!cpaZfp>l@-xp^9&`jb1*lyx~0B3njb9RL`5f}1(L%$?>yUXt~He|qq{?)t8}Jp zGnwu+-!IJ<5hR@bK(VLQ4=ORFPtya6ad`Tay)DhFiNy>HIcK{ zx+_62Nz16qFNB*r2jj(u4 z@_Hxyi)=dU`X|1sHP+s^(P25v%qba`)SrjE(7wq&M?E37ItLwuV`}E$emoL3i!Gt= z42_r5q@j$#b5jxTDqk}pksBr=RwF5Vq&=>s*X$0}TdL*XvO-FJ#JFQ@On)r#qZ(j_ zc|-w`?fVE-%biSE--7ubN3BapIadE0Yx7AOE4o(3>RZ$lK#cS=`Wkxh45!gO1Ml@c z&e#xvaLc)RJxJCWQZ{TNSJM`5$2lp81ZzO&_k}~k+|VZAwjx)ZJkM{Hiayo1ybSdt zr!G`YG%A)%6}<`(4#}{ak^L+HG5aK2=CC6JRN*K%O7B9FslYmdi9%Q>(MBJkz?-s7 zMoAx;CA3c~1qJz&UN~U-pmp#5{$4nJfg(a+3QDu({G=VrM zfL?-3&~LZSJsAspQY2!M%wV*wskcfgq(A1IFkeSYf0w5^Q(0t`PWQURF6|g@exs4( z(#y5QkH$SeH+W0UV)n!dY2#$c{757;+i5fo^QDI7HlETzu9+1)D48IgJ8wi1;`*~( zgN?*2u@eD4rd7T6-1st|@s(pV}0gswXp|i9fEOYX}$hybLZ`Vei-QzZ`*h6JF`hjvdy0dcQ`y|vSFUlHYy0m^l z68nIXwQulQm)md*Uejke?w?=B-n~Ko$)3qs9kEGG7YhdivS(j-|FiT_ba7&^ywLHo zUj=Bg3MzN?msZJh)Cd(;l*jIiL9aWKfCZan?@-0MvKx|?7cd8<+f(qBBR z36AE5uKI}8TsFX!xZy6(1=f5{nOu0`*|lzYtxSWJ~ehfVkoRL zr}tRimo4BuFhUk|OOXCt`{?y)-@R`3h7e3bv*gIvtaS3&!0*IKI<3aa$`V#zj1NIY z2RcM{j^3+Uc?EWb43x`m?U#i6m`roo>or64cd*AzeG}ja$)eDGUGp7Z#5FKzxkncD zL5gq1@1r!0Io8JuF0kxt$?NJ)DO}n5KH1C$0^|46g~byjFSCbX`-s#rQ1e9|rO=Yo?Wb-9d0@fLySKqFPX|5F%T8LJX1v2r zpg2aKu|<>`_mOr(KH`b;Jmo8$d2r33)M2NChsmRwrx^=}IC#iVe&0Ynq|5>38(lHZnH&G$Iltaz4~ANs>R3Bz4~H_c!C|DP?{rLQ(-D zX-8Kq9dR6oh@W8YHc0s13_Y8_xkwaZFRpbwCtler*89$D+L~I2cTjkKa?3z_LZ@g! zqyrK%Y>^jOdM)%*z(b|5hk>_&*zwZYms0c6;`6G+PNbaOOS&ZUGD%sorcx~Pl6QIU zlK09bJr$<&A~AW<%Qfc_xm?*lDTC0iHUk49%N&(!23sYq?>?`34|He>=V zeS9lYMHKJh-6)|TdPBm?hjcKA*9n^A+d`vxvGUm0bt?wAvAa|ejk_HvU)1HVoVXW{ z#i<@>6Lf|8x)kJy&9vD?Ffz|a-BR9k71|*u6K0!e)FF4L$ENL_gi8}IQP3sD3nFNb zv>7DdGUxCVZs|==^1(2kbEU^UCj~Oq@#bvI;%sINM|{7i96g4adq2UUQY^EN&`_Q9 z2*UpQZ70WVW#XlHcx?Z@!wc}cw!86`w&fLXR5$xN#x|eXr#et1f^Vj-C|PZ9uD2#! zy7 z2b}n(ap#rR7m5}oy@e3p?+nv{?2{Si@m5DhPH#o-eGRJA#*(7*zUsU3SouUM&1;ag z&5b!F-T?L?glAvE(V8{a)u<5(*qE_&Tc7Um__5)n4Q2QFrH^O!q6UIdT;$a&)gHve z7335;z;w%0XRta&$`6&{>&nFX_NUXMEhJ=K=@Eok?fsXBxOU646Sj#eZ7o(-A7A9q zD-Y@m+egR?iUzmM%WQYlO=r97<-%OslWlk@({W@W*MU1Q_BK#VH)gLX2D#z=u4Bsidqph?E*$GJ2UZRu74+Blh{**hBNUP)?;Ij%0Y z%n$Z)ki}+4s6koEY+Dz_MY2CVmqJU8YrJP@Np=6FhHozXZ=s8R{0&O0d`MZNUs3-bfd<0ZSq9rQkU;}iP@Sk?wM3o zxf^q38hN%3pB7^G&xKO-E_}OhWCBD*4I0BR!b{b{`3croV{)+9?sF9_8%q^nx}VN3 z&o6j?vnWIc$ zS7}&CV99k0dOPwqj+dlY&w~`KF!o3(r`$--03hvPTDXJTxEEl^ zP_E+X7mQxWveMf0BcRa6_Pgv4y|ErlSRbu8AbyN(Zcp_BMbt&^qG5b;cSlgae958hp#k(Jr+?%}1XbIuej)K66yg5XJ%gZEd^(&;-Teql>B2^mAWz`}@hA#uaP#wUmoHJKri=Ih9Bb zYg$veA$<10)Csy&V=Lr+8Dy&E>-r-DGh;;0&Avl+DvjQJhfEiWb;EE0TU-Gju(5hm z4Gw8*Xm$j4IO{d>(q*+=FE1ymGe?E9@--xV&*VV$?ibkLMKT9*FkRu|*zh^mEkx#h zR9Rp#u*eyiM>YcBLvRO~5;CBraJ-bk1~R8?luH(zGKY@^nKpd&kUV5^Q=+cApN3gP zP6ZIvQuQ6r_nFNh85kV5fNqEe(W?Zl5_|%ThCt znbb(`UOQzlG+qmk)`ptJYqq!m_C0`^QK{0tu}y)Ww=BIPmMh(8CF*&2|2*TS>q z^L%HaDU~1lbVzRL5ve3=$Fvi>6KeaMNffVY1{=~8kcTW`kBXEg6n6kqh^Y~|nwzqJ zrL&VdC$+D_DXtD7odJiJnUWL?(p8B>E|TRl(fg@dPxw|z1} zBN(|)u}CV!v#Md_vMNg*s`MMID);6u+H||@tI8|O`#U(yVz#405<1i@mN^q}sM04GK;R$F-4yL%M!8|B zA)ii|7Zw$`eLnOFhaM8b5TSkn<+rs)|^Z%p10my*-Mz*hFwIAN-6Ii_%Px7ozpeh;@9E5;fD^5g_ALV zur_yWZbQ2bpZ77tUrtF`St&qR7q-1dZf$+{YPjQld5bhMf(;KxI1+e8_MW>e4P|6K zvBW7pMc>)cJxfUiv=7%QJAIllf(zz zai*<3V<~!KajDdWadTy2N*aMHOI~MSOO*1iu?*bzGL=(qX1)WK4xiW4^qk(Ph8E%K z$S?cbs&1U4wtDo4bO>fJ+?;h_1sb=%1jP{eapw5MPZ!W>XAmlse$pF&mvQgAwhvtd)dXx4_G5pi!{ak)UkUaLt}7D_(1F`#H$un(OHOV~8K_4y@v>6!(gK?Ui2-90&4@H>b8a#liyhFX zSNj|tq;6^jLoQH!z><|VGWJ1Ya3?Wr?SpF;r8w1AX1ka3mLsx6#j4}^6{XYJvLjoc z<37{q%rG*n9!n+@$qnXK==QhCAbZ72D*}pOI(28#q~`-G)wG(u<7tPPUjIxs#33;L zT`1?49gj#$bQ}K60V1AlLvFk$st!ck>k&n!>@hrnc#+euX=S83H{=#KO$MZ;XtiFt zW8fRkZls{!lTP!`!;`^p4l2QKq%j1BQAI2xk_{xrc63C>MqsC%UJj>8DrxROGD|lH z`nttJW^AZ%*$Y=}SXKWZ zM0)*eQwyoE!FIV-@TdVe*I6L_Poz};dBSs{{a#`3uSiLpSU;Pkj`o2jZ{w^CO$_*C zUQ~_4HC+5%ee_xp;F4#~#X$HR=cY80GCfUG_RTWu-M9yZ(GXK5#@E=JJ|%`E86aKd zr7rOv3EzNBnSIsuiqypn3AByDd7r)M)j)ZNDEzQu0av9U(%K)yvPiw8=gVl20;D(O zNn$-^7wgMQbuX{jIyYmlm&AZneu)zK#ur2phR7Tu6Jv`!V1Gj}Q*#Er6)csMy0960 zk7mRnE+>4y= z;}=~h>=3tZ21UWXBjfMp?k*;^A|6MhwD0;*O`?=UH4Hl5b$Bk)uA+Q7c3(bjqUU;h zyeBrO(G%o>N0#&v8(Gfl*>&g}oVW0vCrZ^KpW@N-=f0^@^hIi^r1Z z4(wO?vArL+tnv>rGO!!kC=Azg!58p_ zkehol=h>U*8lxr$wLXS+pDQsfClBpwv+JwY2kmGA|0XRy;L2PP1&w`SG;xSFg3+BO z!H*ME(J0*wxdQ@DIDbr}^ZF^hwjC!9suRq{Ieol6Kntta^Kf-v1jdXx zc$p+J-|Tddr6@b^iJH&tuCYfOO(g<2b@?q#nAVxKK~_KT3&*JH?zc)d5di`<89p8= zjeK|fMXEulRwRA%up-BoSmZ<~9|AP}4XB2hx5!eDJ%@Mfnkn@9#_^ICeO$;C*cVl{ zN@6DqZO7UjyB}02q5;gZ$gg1D=RFPV(2q&a#GvQSwtM7D2E}3 z5Z*)1m7RZzQQSwu8?5@Ob~tPrhJTI3E=fwkfI?@CkQagp?g-m;*u|A!dFQVAd`ZpB zoNG9IB_bm?|Jbp9^x1wEp>(_+9twLGH)}Gy$jsEuIgnv32pJZZxCB8>A1v(Z`*qTo z+8PYSQAJ{_9_9pC*m(SeBZEMR3$ZPa9sROP-)#z?!g^5Zi8B7zT(6lEG8yQ6lU-Qx zOU@oGP=|OFQ6R|{dv+%-LUqN&Py>>@=KbRE3^}c{V!dK9Q9=W96sMjH) zxibhPM&O_@4o~Qf;AX-3TRYC+A#vA2B2jVwVe~TRQz>e29lk76oFTh%vmRrHSBZd} z^jTHEywKvdj|h@ZxJ{NipxLwZus}0j!VvCt+Gqzxd4|Fexh@lfL9N>?x9pqw$9 z)1GGyY)4MYK%Emm!l3bqx5szqrhC#qY%0&6vNes?QE2uqmxNIjouPKnVcO$EStmm! zy_56cSaCFx)h4Ky>J?5qPm?$pWW4j?#+SUj4VX^k%xqbmzh%-uxt!7n>Spa!qZBCM z&{ZO&G25^We+pu86fYZ=dgKlo{HjctV9_3yq*2Va2;nG$?7p){XmXF!qQWA6P7_YO zK%WWiiJabF_@SBd`HA#4)I)Wi_T2mtN?v=~+C4q^t)cHtQ3eKsi?^pYmx$hq;jP4ip+v@jk>|gGhe=q^&U)V3N&A+LCS#$lNIJtjQzm2;7=Kkeh z@rRQZ`NjQqv-lhPmkQ$_tQ}Ag0{9~TqsjO;_%9KjKj4GjFYv!5dH&}9buZx$hvWK- z`*lmtimeMerge += clock() - clk; // set the list at the node Vec_PtrFillExtra( p->vCutsNew, Node + 1, NULL ); assert( Cut_NodeReadCutsNew(p, Node) == NULL ); - ///// - pList->pNext = NULL; +// pList->pNext = NULL; ///// - Cut_NodeWriteCutsNew( p, Node, pList ); // filter the cuts //clk = clock(); diff --git a/src/sat/msat/msatActivity.c b/src/sat/msat/msatActivity.c index f808d9bca..239256699 100644 --- a/src/sat/msat/msatActivity.c +++ b/src/sat/msat/msatActivity.c @@ -46,7 +46,7 @@ void Msat_SolverVarBumpActivity( Msat_Solver_t * p, Msat_Lit_t Lit ) return; Var = MSAT_LIT2VAR(Lit); if ( (p->pdActivity[Var] += p->dVarInc) > 1e100 ) -// if ( (p->pdActivity[Var] += p->dVarInc * (1.0 + 0.005*p->pLevel[Var])) > 1e100 ) +// if ( (p->pdActivity[Var] += p->dVarInc * (1.0 + 0.005*p->pActLevels[Var])) > 1e100 ) Msat_SolverVarRescaleActivity( p ); Msat_OrderUpdate( p->pOrder, Var ); } diff --git a/src/sat/msat/msatInt.h b/src/sat/msat/msatInt.h index 15932c67a..7845ec0b5 100644 --- a/src/sat/msat/msatInt.h +++ b/src/sat/msat/msatInt.h @@ -119,7 +119,7 @@ struct Msat_Solver_t_ double dClaDecay; // INVERSE decay factor for clause activity: stores 1/decay. double * pdActivity; // A heuristic measurement of the activity of a variable. - int * pLevels; // the levels of the variables + int * pActLevels; // the levels of the variables double dVarInc; // Amount to bump next variable with. double dVarDecay; // INVERSE decay factor for variable activity: stores 1/decay. Use negative value for static variable order. Msat_Order_t * pOrder; // Keeps track of the decision variable order. diff --git a/src/sat/msat/msatSolverApi.c b/src/sat/msat/msatSolverApi.c index 8c1542df4..9317dcac9 100644 --- a/src/sat/msat/msatSolverApi.c +++ b/src/sat/msat/msatSolverApi.c @@ -174,11 +174,11 @@ Msat_Solver_t * Msat_SolverAlloc( int nVarsAlloc, p->dVarDecay = dVarDecay; p->pdActivity = ALLOC( double, p->nVarsAlloc ); - p->pLevels = ALLOC( int, p->nVarsAlloc ); + p->pActLevels = ALLOC( int, p->nVarsAlloc ); for ( i = 0; i < p->nVarsAlloc; i++ ) { p->pdActivity[i] = 0; - p->pLevels = 0; + p->pActLevels[i] = 0; } p->pAssigns = ALLOC( int, p->nVarsAlloc ); @@ -243,7 +243,7 @@ void Msat_SolverResize( Msat_Solver_t * p, int nVarsAlloc ) p->nVarsAlloc = nVarsAlloc; p->pdActivity = REALLOC( double, p->pdActivity, p->nVarsAlloc ); - p->pLevels = REALLOC( int, p->pLevels, p->nVarsAlloc ); + p->pActLevels = REALLOC( int, p->pActLevels, p->nVarsAlloc ); for ( i = nVarsAllocOld; i < p->nVarsAlloc; i++ ) p->pdActivity[i] = 0; @@ -399,7 +399,7 @@ void Msat_SolverFree( Msat_Solver_t * p ) Msat_ClauseVecFree( p->vLearned ); FREE( p->pdActivity ); - FREE( p->pLevels ); + FREE( p->pActLevels ); Msat_OrderFree( p->pOrder ); for ( i = 0; i < 2 * p->nVarsAlloc; i++ ) diff --git a/src/temp/ivy/ivy.h b/src/temp/ivy/ivy.h index 7fb054f73..a36c795b4 100644 --- a/src/temp/ivy/ivy.h +++ b/src/temp/ivy/ivy.h @@ -66,7 +66,7 @@ typedef enum { } Ivy_Init_t; // the AIG node -struct Ivy_Obj_t_ // 24 bytes (32-bit) or 32 bytes (64-bit) +struct Ivy_Obj_t_ // 24 bytes (32-bit) or 32 bytes (64-bit) // 10 words - 16 words { int Id; // integer ID int TravId; // traversal ID @@ -81,6 +81,10 @@ struct Ivy_Obj_t_ // 24 bytes (32-bit) or 32 bytes (64-bit) Ivy_Obj_t * pFanin0; // fanin Ivy_Obj_t * pFanin1; // fanin Ivy_Obj_t * pFanout; // fanout + Ivy_Obj_t * pNextFan0; // next fanout of the first fanin + Ivy_Obj_t * pNextFan1; // next fanout of the second fanin + Ivy_Obj_t * pPrevFan0; // prev fanout of the first fanin + Ivy_Obj_t * pPrevFan1; // prev fanout of the second fanin Ivy_Obj_t * pEquiv; // equivalent node }; @@ -106,7 +110,8 @@ struct Ivy_Man_t_ int nTravIds; // the traversal ID int nLevelMax; // the maximum level Vec_Int_t * vRequired; // required times - Vec_Ptr_t * vFanouts; // representation of the fanouts +// Vec_Ptr_t * vFanouts; // representation of the fanouts + int fFanout; // fanout is allocated void * pData; // the temporary data void * pCopy; // the temporary data // memory management @@ -384,6 +389,7 @@ extern Ivy_Obj_t * Ivy_CanonExor( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * extern Ivy_Obj_t * Ivy_CanonLatch( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Init_t Init ); /*=== ivyCheck.c ========================================================*/ extern int Ivy_ManCheck( Ivy_Man_t * p ); +extern int Ivy_ManCheckFanouts( Ivy_Man_t * p ); /*=== ivyCut.c ==========================================================*/ extern void Ivy_ManSeqFindCut( Ivy_Man_t * p, Ivy_Obj_t * pNode, Vec_Int_t * vFront, Vec_Int_t * vInside, int nSize ); extern Ivy_Store_t * Ivy_NodeFindCutsAll( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves ); @@ -407,12 +413,10 @@ extern void Ivy_ObjAddFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Ob extern void Ivy_ObjDeleteFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ); extern void Ivy_ObjPatchFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanoutOld, Ivy_Obj_t * pFanoutNew ); extern void Ivy_ObjCollectFanouts( Ivy_Man_t * p, Ivy_Obj_t * pObj, Vec_Ptr_t * vArray ); -extern Ivy_Obj_t * Ivy_ObjReadOneFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj ); extern Ivy_Obj_t * Ivy_ObjReadFirstFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj ); extern int Ivy_ObjFanoutNum( Ivy_Man_t * p, Ivy_Obj_t * pObj ); /*=== ivyIsop.c ==========================================================*/ -extern int Ivy_TruthIsop( unsigned * puTruth, int nVars, Vec_Int_t * vCover ); -extern void Ivy_TruthManStop(); +extern int Ivy_TruthIsop( unsigned * puTruth, int nVars, Vec_Int_t * vCover, int fTryBoth ); /*=== ivyMan.c ==========================================================*/ extern Ivy_Man_t * Ivy_ManStart(); extern void Ivy_ManStop( Ivy_Man_t * p ); @@ -450,6 +454,7 @@ extern Ivy_Obj_t * Ivy_Maj( Ivy_Man_t * p, Ivy_Obj_t * pA, Ivy_Obj_t * pB, I extern Ivy_Obj_t * Ivy_Miter( Ivy_Man_t * p, Vec_Ptr_t * vPairs ); extern Ivy_Obj_t * Ivy_Latch( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Init_t Init ); /*=== ivyResyn.c =========================================================*/ +extern Ivy_Man_t * Ivy_ManResyn0( Ivy_Man_t * p, int fUpdateLevel, int fVerbose ); extern Ivy_Man_t * Ivy_ManResyn( Ivy_Man_t * p, int fUpdateLevel, int fVerbose ); /*=== ivyRewrite.c =========================================================*/ extern int Ivy_ManSeqRewrite( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost ); diff --git a/src/temp/ivy/ivyCheck.c b/src/temp/ivy/ivyCheck.c index 36222f721..ebae64ff0 100644 --- a/src/temp/ivy/ivyCheck.c +++ b/src/temp/ivy/ivyCheck.c @@ -115,7 +115,7 @@ int Ivy_ManCheck( Ivy_Man_t * p ) if ( Ivy_ObjRefs(pObj) == 0 ) printf( "Ivy_ManCheck: Node with ID \"%d\" has no fanouts.\n", pObj->Id ); // check fanouts - if ( p->vFanouts && Ivy_ObjRefs(pObj) != Ivy_ObjFanoutNum(p, pObj) ) + if ( p->fFanout && Ivy_ObjRefs(pObj) != Ivy_ObjFanoutNum(p, pObj) ) printf( "Ivy_ManCheck: Node with ID \"%d\" has mismatch between the number of fanouts and refs.\n", pObj->Id ); } // count the number of nodes in the table @@ -124,9 +124,95 @@ int Ivy_ManCheck( Ivy_Man_t * p ) printf( "Ivy_ManCheck: The number of nodes in the structural hashing table is wrong.\n" ); return 0; } +// if ( !Ivy_ManCheckFanouts(p) ) +// return 0; if ( !Ivy_ManIsAcyclic(p) ) return 0; - return 1; + return 1; +} + +/**Function************************************************************* + + Synopsis [Verifies the fanouts.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Ivy_ManCheckFanouts( Ivy_Man_t * p ) +{ + Vec_Ptr_t * vFanouts; + Ivy_Obj_t * pObj, * pFanout, * pFanin; + int i, k, RetValue = 1; + if ( !p->fFanout ) + return 1; + vFanouts = Vec_PtrAlloc( 100 ); + // make sure every fanin is a fanout + Ivy_ManForEachObj( p, pObj, i ) + { + pFanin = Ivy_ObjFanin0(pObj); + if ( pFanin == NULL ) + continue; + Ivy_ObjForEachFanout( p, pFanin, vFanouts, pFanout, k ) + if ( pFanout == pObj ) + break; + if ( k == Vec_PtrSize(vFanouts) ) + { + printf( "Node %d is a fanin of node %d but the fanout is not there.\n", pFanin->Id, pObj->Id ); + RetValue = 0; + } + + pFanin = Ivy_ObjFanin1(pObj); + if ( pFanin == NULL ) + continue; + Ivy_ObjForEachFanout( p, pFanin, vFanouts, pFanout, k ) + if ( pFanout == pObj ) + break; + if ( k == Vec_PtrSize(vFanouts) ) + { + printf( "Node %d is a fanin of node %d but the fanout is not there.\n", pFanin->Id, pObj->Id ); + RetValue = 0; + } + // check that the previous fanout has the same fanin + if ( pObj->pPrevFan0 ) + { + if ( Ivy_ObjFanin0(pObj->pPrevFan0) != Ivy_ObjFanin0(pObj) && + Ivy_ObjFanin0(pObj->pPrevFan0) != Ivy_ObjFanin1(pObj) && + Ivy_ObjFanin1(pObj->pPrevFan0) != Ivy_ObjFanin0(pObj) && + Ivy_ObjFanin1(pObj->pPrevFan0) != Ivy_ObjFanin1(pObj) ) + { + printf( "Node %d has prev %d without common fanin.\n", pObj->Id, pObj->pPrevFan0->Id ); + RetValue = 0; + } + } + // check that the previous fanout has the same fanin + if ( pObj->pPrevFan1 ) + { + if ( Ivy_ObjFanin0(pObj->pPrevFan1) != Ivy_ObjFanin0(pObj) && + Ivy_ObjFanin0(pObj->pPrevFan1) != Ivy_ObjFanin1(pObj) && + Ivy_ObjFanin1(pObj->pPrevFan1) != Ivy_ObjFanin0(pObj) && + Ivy_ObjFanin1(pObj->pPrevFan1) != Ivy_ObjFanin1(pObj) ) + { + printf( "Node %d has prev %d without common fanin.\n", pObj->Id, pObj->pPrevFan1->Id ); + RetValue = 0; + } + } + } + // make sure every fanout is a fanin + Ivy_ManForEachObj( p, pObj, i ) + { + Ivy_ObjForEachFanout( p, pObj, vFanouts, pFanout, k ) + if ( Ivy_ObjFanin0(pFanout) != pObj && Ivy_ObjFanin1(pFanout) != pObj ) + { + printf( "Node %d is a fanout of node %d but the fanin is not there.\n", pFanout->Id, pObj->Id ); + RetValue = 0; + } + } + Vec_PtrFree( vFanouts ); + return RetValue; } //////////////////////////////////////////////////////////////////////// diff --git a/src/temp/ivy/ivyCut.c b/src/temp/ivy/ivyCut.c index 56f872e9f..65ba4aacb 100644 --- a/src/temp/ivy/ivyCut.c +++ b/src/temp/ivy/ivyCut.c @@ -856,6 +856,24 @@ void Ivy_NodePrintCuts( Ivy_Store_t * pCutStore ) Ivy_NodePrintCut( pCutStore->pCuts + i ); } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline Ivy_Obj_t * Ivy_ObjRealFanin( Ivy_Obj_t * pObj ) +{ + if ( !Ivy_ObjIsBuf(pObj) ) + return pObj; + return Ivy_ObjRealFanin( Ivy_ObjFanin0(pObj) ); +} + /**Function************************************************************* Synopsis [] @@ -911,11 +929,14 @@ Ivy_Store_t * Ivy_NodeFindCutsAll( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves continue; Ivy_NodeCutHash( pCutNew ); */ - iLeaf0 = Ivy_ObjFaninId0(pLeaf); - iLeaf1 = Ivy_ObjFaninId1(pLeaf); + iLeaf0 = Ivy_ObjId( Ivy_ObjRealFanin(Ivy_ObjFanin0(pLeaf)) ); + iLeaf1 = Ivy_ObjId( Ivy_ObjRealFanin(Ivy_ObjFanin1(pLeaf)) ); if ( !Ivy_NodeCutPrescreen( pCut, iLeaf0, iLeaf1 ) ) continue; - Ivy_NodeCutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf0, iLeaf1 ); + if ( iLeaf0 > iLeaf1 ) + Ivy_NodeCutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf1, iLeaf0 ); + else + Ivy_NodeCutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf0, iLeaf1 ); Ivy_NodeCutFindOrAddFilter( pCutStore, pCutNew ); if ( pCutStore->nCuts == IVY_CUT_LIMIT ) break; diff --git a/src/temp/ivy/ivyDfs.c b/src/temp/ivy/ivyDfs.c index 30671baf9..7246ec252 100644 --- a/src/temp/ivy/ivyDfs.c +++ b/src/temp/ivy/ivyDfs.c @@ -265,7 +265,7 @@ int Ivy_ManIsAcyclic_rec( Ivy_Man_t * p, Ivy_Obj_t * pNode ) { if ( Ivy_ObjIsCi(pNode) || Ivy_ObjIsConst1(pNode) ) return 1; - assert( Ivy_ObjIsNode( pNode ) ); + assert( Ivy_ObjIsNode(pNode) || Ivy_ObjIsBuf(pNode) ); // make sure the node is not visited assert( !Ivy_ObjIsTravIdPrevious(p, pNode) ); // check if the node is part of the combinational loop @@ -290,7 +290,7 @@ int Ivy_ManIsAcyclic_rec( Ivy_Man_t * p, Ivy_Obj_t * pNode ) } } // check if the fanin is visited - if ( !Ivy_ObjIsTravIdPrevious(p, Ivy_ObjFanin1(pNode)) ) + if ( Ivy_ObjIsNode(pNode) && !Ivy_ObjIsTravIdPrevious(p, Ivy_ObjFanin1(pNode)) ) { // traverse the fanin's cone searching for the loop if ( !Ivy_ManIsAcyclic_rec(p, Ivy_ObjFanin1(pNode)) ) diff --git a/src/temp/ivy/ivyFanout.c b/src/temp/ivy/ivyFanout.c index 2295516d0..3930186aa 100644 --- a/src/temp/ivy/ivyFanout.c +++ b/src/temp/ivy/ivyFanout.c @@ -24,9 +24,96 @@ /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// -static inline int Ivy_FanoutIsArray( void * p ) { return (int )(((unsigned)p) & 01); } -static inline Vec_Ptr_t * Ivy_FanoutGetArray( void * p ) { assert( Ivy_FanoutIsArray(p) ); return (Vec_Ptr_t *)((unsigned)(p) & ~01); } -static inline Vec_Ptr_t * Ivy_FanoutSetArray( void * p ) { assert( !Ivy_FanoutIsArray(p) ); return (Vec_Ptr_t *)((unsigned)(p) ^ 01); } +// getting hold of the next fanout of the node +static inline Ivy_Obj_t * Ivy_ObjNextFanout( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +{ + assert( !Ivy_IsComplement(pObj) ); + assert( !Ivy_IsComplement(pFanout) ); + if ( pFanout == NULL ) + return NULL; + if ( Ivy_ObjFanin0(pFanout) == pObj ) + return pFanout->pNextFan0; + assert( Ivy_ObjFanin1(pFanout) == pObj ); + return pFanout->pNextFan1; +} + +// getting hold of the previous fanout of the node +static inline Ivy_Obj_t * Ivy_ObjPrevFanout( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +{ + assert( !Ivy_IsComplement(pObj) ); + assert( !Ivy_IsComplement(pFanout) ); + if ( pFanout == NULL ) + return NULL; + if ( Ivy_ObjFanin0(pFanout) == pObj ) + return pFanout->pPrevFan0; + assert( Ivy_ObjFanin1(pFanout) == pObj ); + return pFanout->pPrevFan1; +} + +// getting hold of the place where the next fanout will be attached +static inline Ivy_Obj_t ** Ivy_ObjNextFanoutPlace( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +{ + assert( !Ivy_IsComplement(pObj) ); + assert( !Ivy_IsComplement(pFanout) ); + if ( Ivy_ObjFanin0(pFanout) == pObj ) + return &pFanout->pNextFan0; + assert( Ivy_ObjFanin1(pFanout) == pObj ); + return &pFanout->pNextFan1; +} + +// getting hold of the place where the next fanout will be attached +static inline Ivy_Obj_t ** Ivy_ObjPrevFanoutPlace( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +{ + assert( !Ivy_IsComplement(pObj) ); + assert( !Ivy_IsComplement(pFanout) ); + if ( Ivy_ObjFanin0(pFanout) == pObj ) + return &pFanout->pPrevFan0; + assert( Ivy_ObjFanin1(pFanout) == pObj ); + return &pFanout->pPrevFan1; +} + +// getting hold of the place where the next fanout will be attached +static inline Ivy_Obj_t ** Ivy_ObjPrevNextFanoutPlace( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +{ + Ivy_Obj_t * pTemp; + assert( !Ivy_IsComplement(pObj) ); + assert( !Ivy_IsComplement(pFanout) ); + pTemp = Ivy_ObjPrevFanout(pObj, pFanout); + if ( pTemp == NULL ) + return &pObj->pFanout; + if ( Ivy_ObjFanin0(pTemp) == pObj ) + return &pTemp->pNextFan0; + assert( Ivy_ObjFanin1(pTemp) == pObj ); + return &pTemp->pNextFan1; +} + +// getting hold of the place where the next fanout will be attached +static inline Ivy_Obj_t ** Ivy_ObjNextPrevFanoutPlace( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +{ + Ivy_Obj_t * pTemp; + assert( !Ivy_IsComplement(pObj) ); + assert( !Ivy_IsComplement(pFanout) ); + pTemp = Ivy_ObjNextFanout(pObj, pFanout); + if ( pTemp == NULL ) + return NULL; + if ( Ivy_ObjFanin0(pTemp) == pObj ) + return &pTemp->pPrevFan0; + assert( Ivy_ObjFanin1(pTemp) == pObj ); + return &pTemp->pPrevFan1; +} + +// iterator through the fanouts of the node +#define Ivy_ObjForEachFanoutInt( pObj, pFanout ) \ + for ( pFanout = (pObj)->pFanout; pFanout; \ + pFanout = Ivy_ObjNextFanout(pObj, pFanout) ) + +// safe iterator through the fanouts of the node +#define Ivy_ObjForEachFanoutIntSafe( pObj, pFanout, pFanout2 ) \ + for ( pFanout = (pObj)->pFanout, \ + pFanout2 = Ivy_ObjNextFanout(pObj, pFanout); \ + pFanout; \ + pFanout = pFanout2, \ + pFanout2 = Ivy_ObjNextFanout(pObj, pFanout) ) //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// @@ -47,8 +134,8 @@ void Ivy_ManStartFanout( Ivy_Man_t * p ) { Ivy_Obj_t * pObj; int i; - assert( p->vFanouts == NULL ); - p->vFanouts = Vec_PtrStart( Ivy_ManObjIdMax(p) + 1000 ); + assert( !p->fFanout ); + p->fFanout = 1; Ivy_ManForEachObj( p, pObj, i ) { if ( Ivy_ObjFanin0(pObj) ) @@ -71,14 +158,12 @@ void Ivy_ManStartFanout( Ivy_Man_t * p ) ***********************************************************************/ void Ivy_ManStopFanout( Ivy_Man_t * p ) { - void * pTemp; + Ivy_Obj_t * pObj; int i; - assert( p->vFanouts != NULL ); - Vec_PtrForEachEntry( p->vFanouts, pTemp, i ) - if ( Ivy_FanoutIsArray(pTemp) ) - Vec_PtrFree( Ivy_FanoutGetArray(pTemp) ); - Vec_PtrFree( p->vFanouts ); - p->vFanouts = NULL; + assert( p->fFanout ); + p->fFanout = 0; + Ivy_ManForEachObj( p, pObj, i ) + pObj->pFanout = pObj->pNextFan0 = pObj->pNextFan1 = pObj->pPrevFan0 = pObj->pPrevFan1 = NULL; } /**Function************************************************************* @@ -92,31 +177,15 @@ void Ivy_ManStopFanout( Ivy_Man_t * p ) SeeAlso [] ***********************************************************************/ -void Ivy_ObjAddFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +void Ivy_ObjAddFanout( Ivy_Man_t * p, Ivy_Obj_t * pFanin, Ivy_Obj_t * pFanout ) { - Vec_Ptr_t * vNodes; - void ** ppSpot; - assert( p->vFanouts != NULL ); - assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - // get the pointer to the place where fanouts are stored - ppSpot = Vec_PtrEntryP( p->vFanouts, pObj->Id ); - // consider several cases - if ( *ppSpot == NULL ) // no fanout - add one fanout - *ppSpot = pFanout; - else if ( Ivy_FanoutIsArray(*ppSpot) ) // array of fanouts - add one fanout + assert( p->fFanout ); + if ( pFanin->pFanout ) { - vNodes = Ivy_FanoutGetArray(*ppSpot); - Vec_PtrPush( vNodes, pFanout ); - } - else // only one fanout - create array and put both fanouts into the array - { - vNodes = Vec_PtrAlloc( 4 ); - Vec_PtrPush( vNodes, *ppSpot ); - Vec_PtrPush( vNodes, pFanout ); - *ppSpot = Ivy_FanoutSetArray( vNodes ); + *Ivy_ObjNextFanoutPlace(pFanin, pFanout) = pFanin->pFanout; + *Ivy_ObjPrevFanoutPlace(pFanin, pFanin->pFanout) = pFanout; } + pFanin->pFanout = pFanout; } /**Function************************************************************* @@ -130,30 +199,25 @@ void Ivy_ObjAddFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) SeeAlso [] ***********************************************************************/ -void Ivy_ObjDeleteFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) +void Ivy_ObjDeleteFanout( Ivy_Man_t * p, Ivy_Obj_t * pFanin, Ivy_Obj_t * pFanout ) { - Vec_Ptr_t * vNodes; - void ** ppSpot; - assert( p->vFanouts != NULL ); - assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - ppSpot = Vec_PtrEntryP( p->vFanouts, pObj->Id ); - if ( *ppSpot == NULL ) // no fanout - should not happen - { - assert( 0 ); - } - else if ( Ivy_FanoutIsArray(*ppSpot) ) // the array of fanouts - delete the fanout - { - vNodes = Ivy_FanoutGetArray(*ppSpot); - Vec_PtrRemove( vNodes, pFanout ); - } - else // only one fanout - delete the fanout - { - assert( *ppSpot == pFanout ); - *ppSpot = NULL; - } -// printf( " %d", Ivy_ObjFanoutNum(p, pObj) ); + Ivy_Obj_t ** ppPlace1, ** ppPlace2, ** ppPlaceN; + assert( pFanin->pFanout != NULL ); + + ppPlace1 = Ivy_ObjNextFanoutPlace(pFanin, pFanout); + ppPlaceN = Ivy_ObjPrevNextFanoutPlace(pFanin, pFanout); + assert( *ppPlaceN == pFanout ); + if ( ppPlaceN ) + *ppPlaceN = *ppPlace1; + + ppPlace2 = Ivy_ObjPrevFanoutPlace(pFanin, pFanout); + ppPlaceN = Ivy_ObjNextPrevFanoutPlace(pFanin, pFanout); + assert( ppPlaceN == NULL || *ppPlaceN == pFanout ); + if ( ppPlaceN ) + *ppPlaceN = *ppPlace2; + + *ppPlace1 = NULL; + *ppPlace2 = NULL; } /**Function************************************************************* @@ -167,32 +231,18 @@ void Ivy_ObjDeleteFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout ) SeeAlso [] ***********************************************************************/ -void Ivy_ObjPatchFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanoutOld, Ivy_Obj_t * pFanoutNew ) +void Ivy_ObjPatchFanout( Ivy_Man_t * p, Ivy_Obj_t * pFanin, Ivy_Obj_t * pFanoutOld, Ivy_Obj_t * pFanoutNew ) { - Vec_Ptr_t * vNodes; - void ** ppSpot; - int Index; - assert( p->vFanouts != NULL ); - assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - ppSpot = Vec_PtrEntryP( p->vFanouts, pObj->Id ); - if ( *ppSpot == NULL ) // no fanout - should not happen - { - assert( 0 ); - } - else if ( Ivy_FanoutIsArray(*ppSpot) ) // the array of fanouts - find and replace the fanout - { - vNodes = Ivy_FanoutGetArray(*ppSpot); - Index = Vec_PtrFind( vNodes, pFanoutOld ); - assert( Index >= 0 ); - Vec_PtrWriteEntry( vNodes, Index, pFanoutNew ); - } - else // only one fanout - delete the fanout - { - assert( *ppSpot == pFanoutOld ); - *ppSpot = pFanoutNew; - } + Ivy_Obj_t ** ppPlace; + ppPlace = Ivy_ObjPrevNextFanoutPlace(pFanin, pFanoutOld); + assert( *ppPlace == pFanoutOld ); + if ( ppPlace ) + *ppPlace = pFanoutNew; + ppPlace = Ivy_ObjNextPrevFanoutPlace(pFanin, pFanoutOld); + assert( ppPlace == NULL || *ppPlace == pFanoutOld ); + if ( ppPlace ) + *ppPlace = pFanoutNew; + // assuming that pFanoutNew already points to the next fanout } /**Function************************************************************* @@ -208,52 +258,12 @@ void Ivy_ObjPatchFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanoutOld ***********************************************************************/ void Ivy_ObjCollectFanouts( Ivy_Man_t * p, Ivy_Obj_t * pObj, Vec_Ptr_t * vArray ) { - Vec_Ptr_t * vNodes; - Ivy_Obj_t * pTemp; - int i; - assert( p->vFanouts != NULL ); + Ivy_Obj_t * pFanout; + assert( p->fFanout ); assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - vNodes = Vec_PtrEntry( p->vFanouts, pObj->Id ); - // clean the resulting array Vec_PtrClear( vArray ); - if ( vNodes == NULL ) // no fanout - nothing to do - { - } - else if ( Ivy_FanoutIsArray(vNodes) ) // the array of fanouts - copy fanouts - { - vNodes = Ivy_FanoutGetArray(vNodes); - Vec_PtrForEachEntry( vNodes, pTemp, i ) - Vec_PtrPush( vArray, pTemp ); - } - else // only one fanout - add the fanout - Vec_PtrPush( vArray, vNodes ); -} - -/**Function************************************************************* - - Synopsis [Reads one fanout.] - - Description [Returns fanout if there is only one fanout.] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -Ivy_Obj_t * Ivy_ObjReadOneFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj ) -{ - Vec_Ptr_t * vNodes; - assert( p->vFanouts != NULL ); - assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - vNodes = Vec_PtrEntry( p->vFanouts, pObj->Id ); - // clean the resulting array - if ( vNodes && !Ivy_FanoutIsArray(vNodes) ) // only one fanout - return - return (Ivy_Obj_t *)vNodes; - return NULL; + Ivy_ObjForEachFanoutInt( pObj, pFanout ) + Vec_PtrPush( vArray, pFanout ); } /**Function************************************************************* @@ -269,18 +279,7 @@ Ivy_Obj_t * Ivy_ObjReadOneFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj ) ***********************************************************************/ Ivy_Obj_t * Ivy_ObjReadFirstFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { - Vec_Ptr_t * vNodes; - assert( p->vFanouts != NULL ); - assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - vNodes = Vec_PtrEntry( p->vFanouts, pObj->Id ); - // clean the resulting array - if ( vNodes == NULL ) - return NULL; - if ( !Ivy_FanoutIsArray(vNodes) ) // only one fanout - return - return (Ivy_Obj_t *)vNodes; - return Vec_PtrEntry( Ivy_FanoutGetArray(vNodes), 0 ); + return pObj->pFanout; } /**Function************************************************************* @@ -296,21 +295,13 @@ Ivy_Obj_t * Ivy_ObjReadFirstFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj ) ***********************************************************************/ int Ivy_ObjFanoutNum( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { - Vec_Ptr_t * vNodes; - assert( p->vFanouts != NULL ); - assert( !Ivy_IsComplement(pObj) ); - // extend the fanout array if needed - Vec_PtrFillExtra( p->vFanouts, pObj->Id + 1, NULL ); - vNodes = Vec_PtrEntry( p->vFanouts, pObj->Id ); - // clean the resulting array - if ( vNodes == NULL ) - return 0; - if ( !Ivy_FanoutIsArray(vNodes) ) // only one fanout - return - return 1; - return Vec_PtrSize( Ivy_FanoutGetArray(vNodes) ); + Ivy_Obj_t * pFanout; + int Counter = 0; + Ivy_ObjForEachFanoutInt( pObj, pFanout ) + Counter++; + return Counter; } - //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/temp/ivy/ivyIsop.c b/src/temp/ivy/ivyIsop.c index 2d0101a71..1a4fce25a 100644 --- a/src/temp/ivy/ivyIsop.c +++ b/src/temp/ivy/ivyIsop.c @@ -25,6 +25,10 @@ /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// +// ISOP computation fails if intermediate memory usage exceed this limit +#define IVY_ISOP_MEM_LIMIT 4096 + +// intermediate ISOP representation typedef struct Ivy_Sop_t_ Ivy_Sop_t; struct Ivy_Sop_t_ { @@ -32,122 +36,70 @@ struct Ivy_Sop_t_ int nCubes; }; -static Mem_Flex_t * s_Man = NULL; - -static unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy_Sop_t * pcRes ); -static unsigned Ivy_TruthIsop5_rec( unsigned uOn, unsigned uOnDc, int nVars, Ivy_Sop_t * pcRes ); +// static procedures to compute ISOP +static unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy_Sop_t * pcRes, Vec_Int_t * vStore ); +static unsigned Ivy_TruthIsop5_rec( unsigned uOn, unsigned uOnDc, int nVars, Ivy_Sop_t * pcRes, Vec_Int_t * vStore ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// -/**Function************************************************************* - - Synopsis [Deallocates memory used for computing ISOPs from TTs.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void Ivy_TruthManStop() -{ - Mem_FlexStop( s_Man, 0 ); - s_Man = NULL; -} - /**Function************************************************************* Synopsis [Computes ISOP from TT.] - Description [] + Description [Returns the cover in vCover. Uses the rest of array in vCover + as an intermediate memory storage. Returns the cover with -1 cubes, if the + the computation exceeded the memory limit (IVY_ISOP_MEM_LIMIT words of + intermediate data).] SideEffects [] SeeAlso [] ***********************************************************************/ -int Ivy_TruthIsopOne( unsigned * puTruth, int nVars, Vec_Int_t * vCover ) +int Ivy_TruthIsop( unsigned * puTruth, int nVars, Vec_Int_t * vCover, int fTryBoth ) { Ivy_Sop_t cRes, * pcRes = &cRes; + Ivy_Sop_t cRes2, * pcRes2 = &cRes2; unsigned * pResult; - int i; + int RetValue = 0; assert( nVars >= 0 && nVars < 16 ); // if nVars < 5, make sure it does not depend on those vars - for ( i = nVars; i < 5; i++ ) - assert( !Extra_TruthVarInSupport(puTruth, 5, i) ); +// for ( i = nVars; i < 5; i++ ) +// assert( !Extra_TruthVarInSupport(puTruth, 5, i) ); // prepare memory manager - if ( s_Man == NULL ) - s_Man = Mem_FlexStart(); - else - Mem_FlexRestart( s_Man ); - // compute ISOP - pResult = Ivy_TruthIsop_rec( puTruth, puTruth, nVars, pcRes ); -// Extra_PrintBinary( stdout, puTruth, 1 << nVars ); printf( "\n" ); -// Extra_PrintBinary( stdout, pResult, 1 << nVars ); printf( "\n" ); - assert( Extra_TruthIsEqual( puTruth, pResult, nVars ) ); -//printf( "%d ", Mem_FlexReadMemUsage(s_Man) ); -//printf( "%d ", pcRes->nCubes ); - // copy the truth table Vec_IntClear( vCover ); - for ( i = 0; i < pcRes->nCubes; i++ ) - Vec_IntPush( vCover, pcRes->pCubes[i] ); - return 0; -} - -/**Function************************************************************* - - Synopsis [Computes ISOP from TT.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int Ivy_TruthIsop( unsigned * puTruth, int nVars, Vec_Int_t * vCover ) -{ - Ivy_Sop_t cRes, * pcRes = &cRes; - unsigned * pResult; - int i; - assert( nVars >= 0 && nVars < 16 ); - // if nVars < 5, make sure it does not depend on those vars - for ( i = nVars; i < 5; i++ ) - assert( !Extra_TruthVarInSupport(puTruth, 5, i) ); - // prepare memory manager - if ( s_Man == NULL ) - s_Man = Mem_FlexStart(); - else - Mem_FlexRestart( s_Man ); - // compute ISOP - pResult = Ivy_TruthIsop_rec( puTruth, puTruth, nVars, pcRes ); -// Extra_PrintBinary( stdout, puTruth, 1 << nVars ); printf( "\n" ); -// Extra_PrintBinary( stdout, pResult, 1 << nVars ); printf( "\n" ); - assert( Extra_TruthIsEqual( puTruth, pResult, nVars ) ); -//printf( "%d ", Mem_FlexReadMemUsage(s_Man) ); -//printf( "%d ", pcRes->nCubes ); - // copy the truth table - Vec_IntClear( vCover ); - for ( i = 0; i < pcRes->nCubes; i++ ) - Vec_IntPush( vCover, pcRes->pCubes[i] ); - - // try other polarity - Mem_FlexRestart( s_Man ); - Extra_TruthNot( puTruth, puTruth, nVars ); - pResult = Ivy_TruthIsop_rec( puTruth, puTruth, nVars, pcRes ); - assert( Extra_TruthIsEqual( puTruth, pResult, nVars ) ); - Extra_TruthNot( puTruth, puTruth, nVars ); - if ( Vec_IntSize(vCover) < pcRes->nCubes ) + Vec_IntGrow( vCover, IVY_ISOP_MEM_LIMIT ); + // compute ISOP for the direct polarity + pResult = Ivy_TruthIsop_rec( puTruth, puTruth, nVars, pcRes, vCover ); + if ( pcRes->nCubes == -1 ) + { + vCover->nSize = -1; return 0; - - // copy the truth table - Vec_IntClear( vCover ); - for ( i = 0; i < pcRes->nCubes; i++ ) - Vec_IntPush( vCover, pcRes->pCubes[i] ); - return 1; + } + assert( Extra_TruthIsEqual( puTruth, pResult, nVars ) ); + if ( fTryBoth ) + { + // compute ISOP for the complemented polarity + Extra_TruthNot( puTruth, puTruth, nVars ); + pResult = Ivy_TruthIsop_rec( puTruth, puTruth, nVars, pcRes2, vCover ); + if ( pcRes2->nCubes >= 0 ) + { + assert( Extra_TruthIsEqual( puTruth, pResult, nVars ) ); + if ( pcRes->nCubes > pcRes2->nCubes ) + { + RetValue = 1; + pcRes = pcRes2; + } + } + Extra_TruthNot( puTruth, puTruth, nVars ); + } +// printf( "%d ", vCover->nSize ); + // move the cover representation to the beginning of the memory buffer + memmove( vCover->pArray, pcRes->pCubes, pcRes->nCubes * sizeof(unsigned) ); + Vec_IntShrink( vCover, pcRes->nCubes ); + return RetValue; } /**Function************************************************************* @@ -161,17 +113,22 @@ int Ivy_TruthIsop( unsigned * puTruth, int nVars, Vec_Int_t * vCover ) SeeAlso [] ***********************************************************************/ -unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy_Sop_t * pcRes ) +unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy_Sop_t * pcRes, Vec_Int_t * vStore ) { Ivy_Sop_t cRes0, cRes1, cRes2; Ivy_Sop_t * pcRes0 = &cRes0, * pcRes1 = &cRes1, * pcRes2 = &cRes2; unsigned * puRes0, * puRes1, * puRes2; unsigned * puOn0, * puOn1, * puOnDc0, * puOnDc1, * pTemp, * pTemp0, * pTemp1; int i, k, Var, nWords, nWordsAll; - assert( Extra_TruthIsImply( puOn, puOnDc, nVars ) ); +// assert( Extra_TruthIsImply( puOn, puOnDc, nVars ) ); // allocate room for the resulting truth table nWordsAll = Extra_TruthWordNum( nVars ); - pTemp = (unsigned *)Mem_FlexEntryFetch( s_Man, 4 * nWordsAll ); + pTemp = Vec_IntFetch( vStore, nWordsAll ); + if ( pTemp == NULL ) + { + pcRes->nCubes = -1; + return NULL; + } // check for constants if ( Extra_TruthIsConst0( puOn, nVars ) ) { @@ -183,7 +140,12 @@ unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy if ( Extra_TruthIsConst1( puOnDc, nVars ) ) { pcRes->nCubes = 1; - pcRes->pCubes = (unsigned *)Mem_FlexEntryFetch( s_Man, 4 ); + pcRes->pCubes = Vec_IntFetch( vStore, 1 ); + if ( pcRes->pCubes == NULL ) + { + pcRes->nCubes = -1; + return NULL; + } pcRes->pCubes[0] = 0; Extra_TruthFill( pTemp, nVars ); return pTemp; @@ -198,7 +160,7 @@ unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy // consider a simple case when one-word computation can be used if ( Var < 5 ) { - unsigned uRes = Ivy_TruthIsop5_rec( puOn[0], puOnDc[0], Var+1, pcRes ); + unsigned uRes = Ivy_TruthIsop5_rec( puOn[0], puOnDc[0], Var+1, pcRes, vStore ); for ( i = 0; i < nWordsAll; i++ ) pTemp[i] = uRes; return pTemp; @@ -211,17 +173,37 @@ unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy pTemp0 = pTemp; pTemp1 = pTemp + nWords; // solve for cofactors Extra_TruthSharp( pTemp0, puOn0, puOnDc1, Var ); - puRes0 = Ivy_TruthIsop_rec( pTemp0, puOnDc0, Var, pcRes0 ); + puRes0 = Ivy_TruthIsop_rec( pTemp0, puOnDc0, Var, pcRes0, vStore ); + if ( pcRes0->nCubes == -1 ) + { + pcRes->nCubes = -1; + return NULL; + } Extra_TruthSharp( pTemp1, puOn1, puOnDc0, Var ); - puRes1 = Ivy_TruthIsop_rec( pTemp1, puOnDc1, Var, pcRes1 ); + puRes1 = Ivy_TruthIsop_rec( pTemp1, puOnDc1, Var, pcRes1, vStore ); + if ( pcRes1->nCubes == -1 ) + { + pcRes->nCubes = -1; + return NULL; + } Extra_TruthSharp( pTemp0, puOn0, puRes0, Var ); Extra_TruthSharp( pTemp1, puOn1, puRes1, Var ); Extra_TruthOr( pTemp0, pTemp0, pTemp1, Var ); Extra_TruthAnd( pTemp1, puOnDc0, puOnDc1, Var ); - puRes2 = Ivy_TruthIsop_rec( pTemp0, pTemp1, Var, pcRes2 ); + puRes2 = Ivy_TruthIsop_rec( pTemp0, pTemp1, Var, pcRes2, vStore ); + if ( pcRes2->nCubes == -1 ) + { + pcRes->nCubes = -1; + return NULL; + } // create the resulting cover pcRes->nCubes = pcRes0->nCubes + pcRes1->nCubes + pcRes2->nCubes; - pcRes->pCubes = (unsigned *)Mem_FlexEntryFetch( s_Man, 4 * pcRes->nCubes ); + pcRes->pCubes = Vec_IntFetch( vStore, pcRes->nCubes ); + if ( pcRes->pCubes == NULL ) + { + pcRes->nCubes = -1; + return NULL; + } k = 0; for ( i = 0; i < pcRes0->nCubes; i++ ) pcRes->pCubes[k++] = pcRes0->pCubes[i] | (1 << ((Var<<1)+1)); @@ -255,7 +237,7 @@ unsigned * Ivy_TruthIsop_rec( unsigned * puOn, unsigned * puOnDc, int nVars, Ivy SeeAlso [] ***********************************************************************/ -unsigned Ivy_TruthIsop5_rec( unsigned uOn, unsigned uOnDc, int nVars, Ivy_Sop_t * pcRes ) +unsigned Ivy_TruthIsop5_rec( unsigned uOn, unsigned uOnDc, int nVars, Ivy_Sop_t * pcRes, Vec_Int_t * vStore ) { unsigned uMasks[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; Ivy_Sop_t cRes0, cRes1, cRes2; @@ -273,7 +255,12 @@ unsigned Ivy_TruthIsop5_rec( unsigned uOn, unsigned uOnDc, int nVars, Ivy_Sop_t if ( uOnDc == 0xFFFFFFFF ) { pcRes->nCubes = 1; - pcRes->pCubes = (unsigned *)Mem_FlexEntryFetch( s_Man, 4 ); + pcRes->pCubes = Vec_IntFetch( vStore, 1 ); + if ( pcRes->pCubes == NULL ) + { + pcRes->nCubes = -1; + return 0; + } pcRes->pCubes[0] = 0; return 0xFFFFFFFF; } @@ -292,12 +279,32 @@ unsigned Ivy_TruthIsop5_rec( unsigned uOn, unsigned uOnDc, int nVars, Ivy_Sop_t Extra_TruthCofactor0( &uOnDc0, Var + 1, Var ); Extra_TruthCofactor1( &uOnDc1, Var + 1, Var ); // solve for cofactors - uRes0 = Ivy_TruthIsop5_rec( uOn0 & ~uOnDc1, uOnDc0, Var, pcRes0 ); - uRes1 = Ivy_TruthIsop5_rec( uOn1 & ~uOnDc0, uOnDc1, Var, pcRes1 ); - uRes2 = Ivy_TruthIsop5_rec( (uOn0 & ~uRes0) | (uOn1 & ~uRes1), uOnDc0 & uOnDc1, Var, pcRes2 ); + uRes0 = Ivy_TruthIsop5_rec( uOn0 & ~uOnDc1, uOnDc0, Var, pcRes0, vStore ); + if ( pcRes0->nCubes == -1 ) + { + pcRes->nCubes = -1; + return 0; + } + uRes1 = Ivy_TruthIsop5_rec( uOn1 & ~uOnDc0, uOnDc1, Var, pcRes1, vStore ); + if ( pcRes1->nCubes == -1 ) + { + pcRes->nCubes = -1; + return 0; + } + uRes2 = Ivy_TruthIsop5_rec( (uOn0 & ~uRes0) | (uOn1 & ~uRes1), uOnDc0 & uOnDc1, Var, pcRes2, vStore ); + if ( pcRes2->nCubes == -1 ) + { + pcRes->nCubes = -1; + return 0; + } // create the resulting cover pcRes->nCubes = pcRes0->nCubes + pcRes1->nCubes + pcRes2->nCubes; - pcRes->pCubes = (unsigned *)Mem_FlexEntryFetch( s_Man, 4 * pcRes->nCubes ); + pcRes->pCubes = Vec_IntFetch( vStore, pcRes->nCubes ); + if ( pcRes->pCubes == NULL ) + { + pcRes->nCubes = -1; + return 0; + } k = 0; for ( i = 0; i < pcRes0->nCubes; i++ ) pcRes->pCubes[k++] = pcRes0->pCubes[i] | (1 << ((Var<<1)+1)); diff --git a/src/temp/ivy/ivyMan.c b/src/temp/ivy/ivyMan.c index c5b66ad08..9839567f5 100644 --- a/src/temp/ivy/ivyMan.c +++ b/src/temp/ivy/ivyMan.c @@ -82,7 +82,7 @@ Ivy_Man_t * Ivy_ManStart() void Ivy_ManStop( Ivy_Man_t * p ) { // Ivy_TableProfile( p ); - if ( p->vFanouts ) Ivy_ManStopFanout( p ); +// if ( p->vFanouts ) Ivy_ManStopFanout( p ); if ( p->vChunks ) Ivy_ManStopMemory( p ); if ( p->vRequired ) Vec_IntFree( p->vRequired ); if ( p->vPis ) Vec_PtrFree( p->vPis ); @@ -156,14 +156,14 @@ int Ivy_ManPropagateBuffers( Ivy_Man_t * p, int fUpdateLevel ) void Ivy_ManPrintStats( Ivy_Man_t * p ) { printf( "PI/PO = %d/%d ", Ivy_ManPiNum(p), Ivy_ManPoNum(p) ); - printf( "A = %d. ", Ivy_ManAndNum(p) ); - printf( "L = %d. ", Ivy_ManLatchNum(p) ); + printf( "A = %7d. ", Ivy_ManAndNum(p) ); + printf( "L = %5d. ", Ivy_ManLatchNum(p) ); // printf( "X = %d. ", Ivy_ManExorNum(p) ); - printf( "B = %d. ", Ivy_ManBufNum(p) ); - printf( "MaxID = %d. ", Ivy_ManObjIdMax(p) ); +// printf( "B = %3d. ", Ivy_ManBufNum(p) ); + printf( "MaxID = %7d. ", Ivy_ManObjIdMax(p) ); // printf( "Cre = %d. ", p->nCreated ); // printf( "Del = %d. ", p->nDeleted ); - printf( "Lev = %d. ", Ivy_ManLatchNum(p)? -1 : Ivy_ManLevels(p) ); + printf( "Lev = %3d. ", Ivy_ManLatchNum(p)? -1 : Ivy_ManLevels(p) ); printf( "\n" ); } @@ -190,7 +190,7 @@ void Ivy_ManMakeSeq( Ivy_Man_t * p, int nLatches, int * pInits ) assert( Ivy_ManPoNum(p) == Vec_PtrSize(p->vPos) ); assert( Vec_PtrSize( p->vBufs ) == 0 ); // create fanouts - if ( p->vFanouts == NULL ) + if ( p->fFanout == 0 ) Ivy_ManStartFanout( p ); // collect the POs to be converted into latches for ( i = 0; i < nLatches; i++ ) diff --git a/src/temp/ivy/ivyMem.c b/src/temp/ivy/ivyMem.c index 01833f030..6ca335419 100644 --- a/src/temp/ivy/ivyMem.c +++ b/src/temp/ivy/ivyMem.c @@ -87,15 +87,15 @@ void Ivy_ManAddMemory( Ivy_Man_t * p ) { char * pMemory; int i, nBytes; - assert( sizeof(Ivy_Obj_t) <= 32 ); + assert( sizeof(Ivy_Obj_t) <= 64 ); assert( p->pListFree == NULL ); assert( (Ivy_ManObjNum(p) & IVY_PAGE_MASK) == 0 ); // allocate new memory page - nBytes = sizeof(Ivy_Obj_t) * (1<vChunks, pMemory ); // align memory at the 32-byte boundary - pMemory = pMemory + 32 - (((int)pMemory) & 31); + pMemory = pMemory + 64 - (((int)pMemory) & 63); // remember the manager in the first entry Vec_PtrPush( p->vPages, pMemory ); // break the memory down into nodes diff --git a/src/temp/ivy/ivyObj.c b/src/temp/ivy/ivyObj.c index 735d79c3b..3122c8c82 100644 --- a/src/temp/ivy/ivyObj.c +++ b/src/temp/ivy/ivyObj.c @@ -79,6 +79,7 @@ Ivy_Obj_t * Ivy_ObjCreate( Ivy_Man_t * p, Ivy_Obj_t * pGhost ) assert( Ivy_TableLookup(p, pGhost) == NULL ); // get memory for the new object pObj = Ivy_ManFetchMemory( p ); +//printf( "Reusing %p.\n", pObj ); assert( Ivy_ObjIsNone(pObj) ); pObj->Id = Vec_PtrSize(p->vObjs); Vec_PtrPush( p->vObjs, pObj ); @@ -139,13 +140,13 @@ void Ivy_ObjConnect( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFan0, Ivy_Obj if ( Ivy_ObjFanin0(pObj) != NULL ) { Ivy_ObjRefsInc( Ivy_ObjFanin0(pObj) ); - if ( p->vFanouts ) + if ( p->fFanout ) Ivy_ObjAddFanout( p, Ivy_ObjFanin0(pObj), pObj ); } if ( Ivy_ObjFanin1(pObj) != NULL ) { Ivy_ObjRefsInc( Ivy_ObjFanin1(pObj) ); - if ( p->vFanouts ) + if ( p->fFanout ) Ivy_ObjAddFanout( p, Ivy_ObjFanin1(pObj), pObj ); } // add the node to the structural hash table @@ -168,23 +169,29 @@ void Ivy_ObjDisconnect( Ivy_Man_t * p, Ivy_Obj_t * pObj ) assert( !Ivy_IsComplement(pObj) ); assert( Ivy_ObjIsPi(pObj) || Ivy_ObjIsOneFanin(pObj) || Ivy_ObjFanin1(pObj) != NULL ); // remove connections - if ( Ivy_ObjFanin0(pObj) != NULL ) + if ( pObj->pFanin0 != NULL ) { Ivy_ObjRefsDec(Ivy_ObjFanin0(pObj)); - if ( p->vFanouts ) + if ( p->fFanout ) Ivy_ObjDeleteFanout( p, Ivy_ObjFanin0(pObj), pObj ); } - if ( Ivy_ObjFanin1(pObj) != NULL ) + if ( pObj->pFanin1 != NULL ) { Ivy_ObjRefsDec(Ivy_ObjFanin1(pObj)); - if ( p->vFanouts ) + if ( p->fFanout ) Ivy_ObjDeleteFanout( p, Ivy_ObjFanin1(pObj), pObj ); } + assert( pObj->pNextFan0 == NULL ); + assert( pObj->pNextFan1 == NULL ); + assert( pObj->pPrevFan0 == NULL ); + assert( pObj->pPrevFan1 == NULL ); // remove the node from the structural hash table Ivy_TableDelete( p, pObj ); // add the first fanin pObj->pFanin0 = NULL; pObj->pFanin1 = NULL; + +// Ivy_ManCheckFanouts( p ); } /**Function************************************************************* @@ -205,14 +212,14 @@ void Ivy_ObjPatchFanin0( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFaninNew pFaninOld = Ivy_ObjFanin0(pObj); // decrement ref and remove fanout Ivy_ObjRefsDec( pFaninOld ); - if ( p->vFanouts ) + if ( p->fFanout ) Ivy_ObjDeleteFanout( p, pFaninOld, pObj ); - // increment ref and add fanout - Ivy_ObjRefsInc( Ivy_Regular(pFaninNew) ); - if ( p->vFanouts ) - Ivy_ObjAddFanout( p, Ivy_Regular(pFaninNew), pObj ); // update the fanin pObj->pFanin0 = pFaninNew; + // increment ref and add fanout + Ivy_ObjRefsInc( Ivy_Regular(pFaninNew) ); + if ( p->fFanout ) + Ivy_ObjAddFanout( p, Ivy_Regular(pFaninNew), pObj ); // get rid of old fanin if ( !Ivy_ObjIsPi(pFaninOld) && Ivy_ObjRefs(pFaninOld) == 0 ) Ivy_ObjDelete_rec( p, pFaninOld, 1 ); @@ -243,7 +250,7 @@ void Ivy_ObjDelete( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fFreeTop ) Vec_PtrRemove( p->vPis, pObj ); else if ( Ivy_ObjIsPo(pObj) ) Vec_PtrRemove( p->vPos, pObj ); - else if ( p->vFanouts && Ivy_ObjIsBuf(pObj) ) + else if ( p->fFanout && Ivy_ObjIsBuf(pObj) ) Vec_PtrRemove( p->vBufs, pObj ); // clean and recycle the entry if ( fFreeTop ) @@ -251,11 +258,14 @@ void Ivy_ObjDelete( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fFreeTop ) // free the node Vec_PtrWriteEntry( p->vObjs, pObj->Id, NULL ); Ivy_ManRecycleMemory( p, pObj ); +//printf( "Recycling after delete %p.\n", pObj ); } else { int nRefsOld = pObj->nRefs; + Ivy_Obj_t * pFanout = pObj->pFanout; Ivy_ObjClean( pObj ); + pObj->pFanout = pFanout; pObj->nRefs = nRefsOld; } } @@ -318,7 +328,7 @@ void Ivy_ObjReplace( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew, in if ( fUpdateLevel ) { // if the new node's arrival time is different, recursively update arrival time of the fanouts - if ( p->vFanouts && !Ivy_ObjIsBuf(pObjNew) && pObjOld->Level != pObjNew->Level ) + if ( p->fFanout && !Ivy_ObjIsBuf(pObjNew) && pObjOld->Level != pObjNew->Level ) { assert( Ivy_ObjIsNode(pObjOld) ); pObjOld->Level = pObjNew->Level; @@ -338,16 +348,23 @@ void Ivy_ObjReplace( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew, in // delete the old object if ( fDeleteOld ) Ivy_ObjDelete_rec( p, pObjOld, fFreeTop ); - // make sure object is pointing to itself + // make sure object is not pointing to itself assert( Ivy_ObjFanin0(pObjNew) == NULL || pObjOld != Ivy_ObjFanin0(pObjNew) ); assert( Ivy_ObjFanin1(pObjNew) == NULL || pObjOld != Ivy_ObjFanin1(pObjNew) ); + // make sure the old node has no fanin fanout pointers + if ( p->fFanout ) + { + assert( pObjOld->pFanout != NULL ); + assert( pObjNew->pFanout == NULL ); + pObjNew->pFanout = pObjOld->pFanout; + } // transfer the old object assert( Ivy_ObjRefs(pObjNew) == 0 ); nRefsOld = pObjOld->nRefs; Ivy_ObjOverwrite( pObjOld, pObjNew ); pObjOld->nRefs = nRefsOld; // patch the fanout of the fanins - if ( p->vFanouts ) + if ( p->fFanout ) { Ivy_ObjPatchFanout( p, Ivy_ObjFanin0(pObjOld), pObjNew, pObjOld ); if ( Ivy_ObjFanin1(pObjOld) ) @@ -358,9 +375,12 @@ void Ivy_ObjReplace( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew, in // recycle the object that was taken over by pObjOld Vec_PtrWriteEntry( p->vObjs, pObjNew->Id, NULL ); Ivy_ManRecycleMemory( p, pObjNew ); +//printf( "Recycling after patch %p.\n", pObjNew ); // if the new node is the buffer propagate it - if ( p->vFanouts && Ivy_ObjIsBuf(pObjOld) ) + if ( p->fFanout && Ivy_ObjIsBuf(pObjOld) ) Vec_PtrPush( p->vBufs, pObjOld ); +// Ivy_ManCheckFanouts( p ); +// printf( "\n" ); } /**Function************************************************************* @@ -385,6 +405,7 @@ void Ivy_NodeFixBufferFanins( Ivy_Man_t * p, Ivy_Obj_t * pNode, int fUpdateLevel return; pFanReal0 = Ivy_ObjReal( Ivy_ObjChild0(pNode) ); Ivy_ObjPatchFanin0( p, pNode, pFanReal0 ); +// Ivy_ManCheckFanouts( p ); return; } if ( !Ivy_ObjIsBuf(Ivy_ObjFanin0(pNode)) && !Ivy_ObjIsBuf(Ivy_ObjFanin1(pNode)) ) diff --git a/src/temp/ivy/ivyResyn.c b/src/temp/ivy/ivyResyn.c index 804bdfb4e..b2e4a4dd2 100644 --- a/src/temp/ivy/ivyResyn.c +++ b/src/temp/ivy/ivyResyn.c @@ -28,6 +28,47 @@ /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// +/**Function************************************************************* + + Synopsis [Performs several passes of rewriting on the AIG.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Ivy_Man_t * Ivy_ManResyn0( Ivy_Man_t * pMan, int fUpdateLevel, int fVerbose ) +{ + int clk; + Ivy_Man_t * pTemp; + +if ( fVerbose ) { printf( "Original:\n" ); } +if ( fVerbose ) Ivy_ManPrintStats( pMan ); + +clk = clock(); + pMan = Ivy_ManBalance( pMan, fUpdateLevel ); +if ( fVerbose ) { printf( "\n" ); } +if ( fVerbose ) { PRT( "Balance", clock() - clk ); } +if ( fVerbose ) Ivy_ManPrintStats( pMan ); + +// Ivy_ManRewriteAlg( pMan, fUpdateLevel, 0 ); +clk = clock(); + Ivy_ManRewritePre( pMan, fUpdateLevel, 0, 0 ); +if ( fVerbose ) { printf( "\n" ); } +if ( fVerbose ) { PRT( "Rewrite", clock() - clk ); } +if ( fVerbose ) Ivy_ManPrintStats( pMan ); + +clk = clock(); + pMan = Ivy_ManBalance( pTemp = pMan, fUpdateLevel ); + Ivy_ManStop( pTemp ); +if ( fVerbose ) { printf( "\n" ); } +if ( fVerbose ) { PRT( "Balance", clock() - clk ); } +if ( fVerbose ) Ivy_ManPrintStats( pMan ); + return pMan; +} + /**Function************************************************************* Synopsis [Performs several passes of rewriting on the AIG.] diff --git a/src/temp/ivy/ivyRwrPre.c b/src/temp/ivy/ivyRwrPre.c index 537b64ffc..643315797 100644 --- a/src/temp/ivy/ivyRwrPre.c +++ b/src/temp/ivy/ivyRwrPre.c @@ -61,7 +61,7 @@ int Ivy_ManRewritePre( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost, int fV if ( pManRwt == NULL ) return 0; // create fanouts - if ( fUpdateLevel && p->vFanouts == NULL ) + if ( fUpdateLevel && p->fFanout == 0 ) Ivy_ManStartFanout( p ); // compute the reverse levels if level update is requested if ( fUpdateLevel ) diff --git a/src/temp/ivy/ivySeq.c b/src/temp/ivy/ivySeq.c index 8fd1b63b7..7cf55b69e 100644 --- a/src/temp/ivy/ivySeq.c +++ b/src/temp/ivy/ivySeq.c @@ -64,7 +64,7 @@ int Ivy_ManRewriteSeq( Ivy_Man_t * p, int fUseZeroCost, int fVerbose ) if ( pManRwt == NULL ) return 0; // create fanouts - if ( p->vFanouts == NULL ) + if ( p->fFanout == 0 ) Ivy_ManStartFanout( p ); // resynthesize each node once nNodes = Ivy_ManObjIdMax(p); diff --git a/src/temp/ivy/ivyUtil.c b/src/temp/ivy/ivyUtil.c index 77a55a398..a23e76c91 100644 --- a/src/temp/ivy/ivyUtil.c +++ b/src/temp/ivy/ivyUtil.c @@ -381,7 +381,7 @@ void Ivy_ObjUpdateLevel_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj ) Ivy_Obj_t * pFanout; Vec_Ptr_t * vFanouts; int i, LevelNew; - assert( p->vFanouts ); + assert( p->fFanout ); assert( Ivy_ObjIsNode(pObj) ); vFanouts = Vec_PtrAlloc( 10 ); Ivy_ObjForEachFanout( p, pObj, vFanouts, pFanout, i ) @@ -416,7 +416,7 @@ int Ivy_ObjLevelRNew( Ivy_Man_t * p, Ivy_Obj_t * pObj ) Ivy_Obj_t * pFanout; Vec_Ptr_t * vFanouts; int i, Required, LevelNew = 1000000; - assert( p->vFanouts && p->vRequired ); + assert( p->fFanout && p->vRequired ); vFanouts = Vec_PtrAlloc( 10 ); Ivy_ObjForEachFanout( p, pObj, vFanouts, pFanout, i ) { diff --git a/src/temp/player/player.h b/src/temp/player/player.h index b0bb0ec48..0213683fe 100644 --- a/src/temp/player/player.h +++ b/src/temp/player/player.h @@ -86,13 +86,14 @@ static inline Pla_Obj_t * Ivy_ObjPlaStr( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { //////////////////////////////////////////////////////////////////////// /*=== playerToAbc.c ==============================================================*/ -extern void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int fFastMode, int fVerbose ); +extern void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int fFastMode, int fRewriting, int fSynthesis, int fVerbose ); /*=== playerCore.c =============================================================*/ extern Pla_Man_t * Pla_ManDecompose( Ivy_Man_t * p, int nLutMax, int nPlaMax, int fVerbose ); /*=== playerFast.c =============================================================*/ extern void Pla_ManFastLutMap( Ivy_Man_t * pAig, int nLimit ); extern void Pla_ManFastLutMapStop( Ivy_Man_t * pAig ); extern void Pla_ManFastLutMapReadSupp( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Vec_Int_t * vLeaves ); +extern void Pla_ManFastLutMapReverseLevel( Ivy_Man_t * pAig ); /*=== playerMan.c ==============================================================*/ extern Pla_Man_t * Pla_ManAlloc( Ivy_Man_t * p, int nLutMax, int nPlaMax ); extern void Pla_ManFree( Pla_Man_t * p ); diff --git a/src/temp/player/playerMan.c b/src/temp/player/playerMan.c index 1196d2422..78b207188 100644 --- a/src/temp/player/playerMan.c +++ b/src/temp/player/playerMan.c @@ -40,7 +40,7 @@ ***********************************************************************/ Pla_Man_t * Pla_ManAlloc( Ivy_Man_t * pAig, int nLutMax, int nPlaMax ) -{ +{ Pla_Man_t * pMan; assert( !(nLutMax < 2 || nLutMax > 8 || nPlaMax < 8 || nPlaMax > 128) ); // start the manager diff --git a/src/temp/player/playerToAbc.c b/src/temp/player/playerToAbc.c index fc5e01ea8..91994ca6c 100644 --- a/src/temp/player/playerToAbc.c +++ b/src/temp/player/playerToAbc.c @@ -50,9 +50,8 @@ static inline Abc_Obj_t * Abc_ObjGetIvy2Abc( Ivy_Man_t * p, int IvyId ) SeeAlso [] ***********************************************************************/ -void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int fFastMode, int fVerbose ) +void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int fFastMode, int fRewriting, int fSynthesis, int fVerbose ) { - int fUseRewriting = 0; Pla_Man_t * p; Ivy_Man_t * pMan, * pManExt; Abc_Ntk_t * pNtkNew; @@ -69,7 +68,15 @@ void * Abc_NtkPlayer( void * pNtk, int nLutMax, int nPlaMax, int RankCost, int f } if ( fVerbose ) Ivy_ManPrintStats( pMan ); - if ( fUseRewriting ) + if ( fRewriting ) + { + // simplify + pMan = Ivy_ManResyn0( pManExt = pMan, 1, 0 ); + Ivy_ManStop( pManExt ); + if ( fVerbose ) + Ivy_ManPrintStats( pMan ); + } + if ( fSynthesis ) { // simplify pMan = Ivy_ManResyn( pManExt = pMan, 1, 0 ); @@ -261,9 +268,16 @@ Abc_Obj_t * Ivy_ManToAbc_rec( Abc_Ntk_t * pNtkNew, Ivy_Man_t * pMan, Pla_Man_t * pObjAbc->pData = Abc_SopCreateAnd( pNtkNew->pManFunc, Vec_IntSize(vSupp), NULL ); pObjAbc = Abc_NodeCreateConst0( pNtkNew ); } + else if ( Extra_TruthIsConst1(puTruth, 8) ) + { + pObjAbc->pData = Abc_SopCreateAnd( pNtkNew->pManFunc, Vec_IntSize(vSupp), NULL ); + pObjAbc = Abc_NodeCreateConst1( pNtkNew ); + } else { - int fCompl = Ivy_TruthIsop( puTruth, Vec_IntSize(vSupp), vNodes ); + int fCompl = Ivy_TruthIsop( puTruth, Vec_IntSize(vSupp), vNodes, 1 ); + if ( vNodes->nSize == -1 ) + printf( "Ivy_ManToAbc_rec(): Internal error.\n" ); pObjAbc->pData = Abc_SopCreateFromIsop( pNtkNew->pManFunc, Vec_IntSize(vSupp), vNodes ); if ( fCompl ) Abc_SopComplement(pObjAbc->pData); // printf( "Cover contains %d cubes.\n", Vec_IntSize(vNodes) ); @@ -372,9 +386,16 @@ Abc_Obj_t * Ivy_ManToAbcFast_rec( Abc_Ntk_t * pNtkNew, Ivy_Man_t * pMan, Ivy_Obj pObjAbc->pData = Abc_SopCreateAnd( pNtkNew->pManFunc, Vec_IntSize(vSupp), NULL ); pObjAbc = Abc_NodeCreateConst0( pNtkNew ); } + else if ( Extra_TruthIsConst1(puTruth, 8) ) + { + pObjAbc->pData = Abc_SopCreateAnd( pNtkNew->pManFunc, Vec_IntSize(vSupp), NULL ); + pObjAbc = Abc_NodeCreateConst1( pNtkNew ); + } else { - int fCompl = Ivy_TruthIsop( puTruth, Vec_IntSize(vSupp), vNodes ); + int fCompl = Ivy_TruthIsop( puTruth, Vec_IntSize(vSupp), vNodes, 1 ); + if ( vNodes->nSize == -1 ) + printf( "Ivy_ManToAbcFast_rec(): Internal error.\n" ); pObjAbc->pData = Abc_SopCreateFromIsop( pNtkNew->pManFunc, Vec_IntSize(vSupp), vNodes ); if ( fCompl ) Abc_SopComplement(pObjAbc->pData); } @@ -444,32 +465,48 @@ static inline int Abc_NtkPlayerCostOne( int nCost, int RankCost ) int Abc_NtkPlayerCost( Abc_Ntk_t * pNtk, int RankCost, int fVerbose ) { Abc_Obj_t * pObj; - int nFanins, nLevels, * pLevelCosts, CostTotal, nRanksTotal, i; + int * pLevelCosts, * pLevelCostsR; + int nFanins, nLevels, LevelR, Cost, CostTotal, CostTotalR, nRanksTotal, nRanksTotalR, i; + // compute the reverse levels + Abc_NtkStartReverseLevels( pNtk ); // compute the costs for each level nLevels = Abc_NtkGetLevelNum( pNtk ); - pLevelCosts = ALLOC( int, nLevels + 1 ); - memset( pLevelCosts, 0, sizeof(int) * (nLevels + 1) ); + pLevelCosts = ALLOC( int, nLevels + 1 ); + pLevelCostsR = ALLOC( int, nLevels + 1 ); + memset( pLevelCosts, 0, sizeof(int) * (nLevels + 1) ); + memset( pLevelCostsR, 0, sizeof(int) * (nLevels + 1) ); Abc_NtkForEachNode( pNtk, pObj, i ) { nFanins = Abc_ObjFaninNum(pObj); if ( nFanins == 0 ) continue; - pLevelCosts[ pObj->Level ] += Abc_NodePlayerCost( nFanins ); + Cost = Abc_NodePlayerCost( nFanins ); + LevelR = Vec_IntEntry( pNtk->vLevelsR, pObj->Id ); + pLevelCosts[ pObj->Level ] += Cost; + pLevelCostsR[ LevelR ] += Cost; } // compute the total cost - CostTotal = nRanksTotal = 0; - for ( i = 1; i <= nLevels; i++ ) + CostTotal = CostTotalR = nRanksTotal = nRanksTotalR = 0; + for ( i = 0; i <= nLevels; i++ ) { - CostTotal += pLevelCosts[i]; - nRanksTotal += Abc_NtkPlayerCostOne( pLevelCosts[i], RankCost ); + CostTotal += pLevelCosts[i]; + CostTotalR += pLevelCostsR[i]; + nRanksTotal += Abc_NtkPlayerCostOne( pLevelCosts[i], RankCost ); + nRanksTotalR += Abc_NtkPlayerCostOne( pLevelCostsR[i], RankCost ); } + assert( CostTotal == CostTotalR ); // print out statistics if ( fVerbose ) { for ( i = 1; i <= nLevels; i++ ) - printf( "Level %2d : Cost = %6d. Ranks = %6.3f.\n", i, pLevelCosts[i], ((double)pLevelCosts[i])/RankCost ); - printf( "TOTAL : Cost = %6d. Ranks = %3d.\n", CostTotal, nRanksTotal ); + printf( "Level %2d : Cost = %7d. Ranks = %6.3f. Cost = %7d. Ranks = %6.3f.\n", i, + pLevelCosts[i], ((double)pLevelCosts[i])/RankCost, + pLevelCostsR[nLevels+1-i], ((double)pLevelCostsR[nLevels+1-i])/RankCost ); + printf( "TOTAL : Cost = %7d. Ranks = %6d. RanksR = %5d. RanksBest = %5d.\n", + CostTotal, nRanksTotal, nRanksTotalR, nLevels ); } + free( pLevelCosts ); + free( pLevelCostsR ); return nRanksTotal; } diff --git a/src/temp/vec/vecInt.h b/src/temp/vec/vecInt.h index 9db30af71..4a97fc919 100644 --- a/src/temp/vec/vecInt.h +++ b/src/temp/vec/vecInt.h @@ -278,23 +278,6 @@ static inline int Vec_IntEntry( Vec_Int_t * p, int i ) return p->pArray[i]; } -/**Function************************************************************* - - Synopsis [] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -static inline int * Vec_IntEntryP( Vec_Int_t * p, int i ) -{ - assert( i >= 0 && i < p->nSize ); - return p->pArray + i; -} - /**Function************************************************************* Synopsis [] @@ -402,10 +385,7 @@ static inline void Vec_IntFillExtra( Vec_Int_t * p, int nSize, int Entry ) int i; if ( p->nSize >= nSize ) return; - if ( p->nSize < 2 * nSize ) - Vec_IntGrow( p, 2 * nSize ); - else - Vec_IntGrow( p, p->nSize ); + Vec_IntGrow( p, nSize ); for ( i = p->nSize; i < nSize; i++ ) p->pArray[i] = Entry; p->nSize = nSize; @@ -601,6 +581,28 @@ static inline int Vec_IntPushUnique( Vec_Int_t * p, int Entry ) return 0; } +/**Function************************************************************* + + Synopsis [Returns the pointer to the next nWords entries in the vector.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline unsigned * Vec_IntFetch( Vec_Int_t * p, int nWords ) +{ + p->nSize += nWords; + if ( p->nSize > p->nCap ) + { +// Vec_IntGrow( p, 2 * p->nSize ); + return NULL; + } + return ((unsigned *)p->pArray) + p->nSize - nWords; +} + /**Function************************************************************* Synopsis [Returns the last entry and removes it from the list.] diff --git a/src/temp/vec/vecPtr.h b/src/temp/vec/vecPtr.h index 96975ff0c..07ac0f17e 100644 --- a/src/temp/vec/vecPtr.h +++ b/src/temp/vec/vecPtr.h @@ -282,6 +282,23 @@ static inline void * Vec_PtrEntry( Vec_Ptr_t * p, int i ) return p->pArray[i]; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void ** Vec_PtrEntryP( Vec_Ptr_t * p, int i ) +{ + assert( i >= 0 && i < p->nSize ); + return p->pArray + i; +} + /**Function************************************************************* Synopsis [] @@ -371,7 +388,10 @@ static inline void Vec_PtrFillExtra( Vec_Ptr_t * p, int nSize, void * Entry ) int i; if ( p->nSize >= nSize ) return; - Vec_PtrGrow( p, nSize ); + if ( p->nSize < 2 * nSize ) + Vec_PtrGrow( p, 2 * nSize ); + else + Vec_PtrGrow( p, p->nSize ); for ( i = p->nSize; i < nSize; i++ ) p->pArray[i] = Entry; p->nSize = nSize; @@ -505,10 +525,18 @@ static inline int Vec_PtrFind( Vec_Ptr_t * p, void * Entry ) static inline void Vec_PtrRemove( Vec_Ptr_t * p, void * Entry ) { int i; + // delete assuming that it is closer to the end + for ( i = p->nSize - 1; i >= 0; i-- ) + if ( p->pArray[i] == Entry ) + break; + assert( i >= 0 ); +/* + // delete assuming that it is closer to the beginning for ( i = 0; i < p->nSize; i++ ) if ( p->pArray[i] == Entry ) break; assert( i < p->nSize ); +*/ for ( i++; i < p->nSize; i++ ) p->pArray[i-1] = p->pArray[i]; p->nSize--;