summaryrefslogtreecommitdiffstats
path: root/src/aig/ivy
diff options
context:
space:
mode:
authorAlan Mishchenko <alanmi@berkeley.edu>2007-10-01 08:01:00 -0700
committerAlan Mishchenko <alanmi@berkeley.edu>2007-10-01 08:01:00 -0700
commit4812c90424dfc40d26725244723887a2d16ddfd9 (patch)
treeb32ace96e7e2d84d586e09ba605463b6f49c3271 /src/aig/ivy
parente54d9691616b9a0326e2fdb3156bb4eeb8abfcd7 (diff)
downloadabc-4812c90424dfc40d26725244723887a2d16ddfd9.tar.gz
abc-4812c90424dfc40d26725244723887a2d16ddfd9.tar.bz2
abc-4812c90424dfc40d26725244723887a2d16ddfd9.zip
Version abc71001
Diffstat (limited to 'src/aig/ivy')
-rw-r--r--src/aig/ivy/attr.h414
-rw-r--r--src/aig/ivy/ivy.h557
-rw-r--r--src/aig/ivy/ivyBalance.c404
-rw-r--r--src/aig/ivy/ivyCanon.c144
-rw-r--r--src/aig/ivy/ivyCheck.c273
-rw-r--r--src/aig/ivy/ivyCut.c989
-rw-r--r--src/aig/ivy/ivyCutTrav.c473
-rw-r--r--src/aig/ivy/ivyDfs.c493
-rw-r--r--src/aig/ivy/ivyDsd.c819
-rw-r--r--src/aig/ivy/ivyFanout.c309
-rw-r--r--src/aig/ivy/ivyFastMap.c1593
-rw-r--r--src/aig/ivy/ivyFraig.c2760
-rw-r--r--src/aig/ivy/ivyHaig.c530
-rw-r--r--src/aig/ivy/ivyMan.c546
-rw-r--r--src/aig/ivy/ivyMem.c116
-rw-r--r--src/aig/ivy/ivyMulti.c301
-rw-r--r--src/aig/ivy/ivyMulti8.c427
-rw-r--r--src/aig/ivy/ivyObj.c476
-rw-r--r--src/aig/ivy/ivyOper.c293
-rw-r--r--src/aig/ivy/ivyResyn.c196
-rw-r--r--src/aig/ivy/ivyRwr.c609
-rw-r--r--src/aig/ivy/ivyRwrAlg.c408
-rw-r--r--src/aig/ivy/ivySeq.c1134
-rw-r--r--src/aig/ivy/ivyShow.c338
-rw-r--r--src/aig/ivy/ivyTable.c301
-rw-r--r--src/aig/ivy/ivyUtil.c818
-rw-r--r--src/aig/ivy/ivy_.c48
-rw-r--r--src/aig/ivy/module.make22
28 files changed, 15791 insertions, 0 deletions
diff --git a/src/aig/ivy/attr.h b/src/aig/ivy/attr.h
new file mode 100644
index 00000000..16cf0b84
--- /dev/null
+++ b/src/aig/ivy/attr.h
@@ -0,0 +1,414 @@
+/**CFile****************************************************************
+
+ FileName [attr.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [Network attributes.]
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - June 20, 2005.]
+
+ Revision [$Id: attr.h,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __ATTR_H__
+#define __ATTR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include "extra.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Attr_ManStruct_t_ Attr_Man_t;
+struct Attr_ManStruct_t_
+{
+ // attribute info
+ int nAttrSize; // the size of each attribute in bytes
+ Extra_MmFixed_t * pManMem; // memory manager for attributes
+ int nAttrs; // the number of attributes allocated
+ void ** pAttrs; // the array of attributes
+ int fUseInt; // uses integer attributes
+ // attribute specific info
+ void * pManAttr; // the manager for this attribute
+ void (*pFuncFreeMan) (void *); // the procedure to call to free attribute-specific manager
+ void (*pFuncFreeObj) (void *, void *); // the procedure to call to free attribute-specific data
+};
+
+// at any time, an attribute of the given ID can be
+// - not available (p->nAttrs < Id)
+// - available but not allocated (p->nAttrs >= Id && p->pAttrs[Id] == NULL)
+// - available and allocated (p->nAttrs >= Id && p->pAttrs[Id] != NULL)
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Allocates the attribute manager.]
+
+ Description [The manager is simple if it does not need memory manager.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Attr_Man_t * Attr_ManAlloc( int nAttrSize, int fManMem )
+{
+ Attr_Man_t * p;
+ p = ALLOC( Attr_Man_t, 1 );
+ memset( p, 0, sizeof(Attr_Man_t) );
+ p->nAttrSize = nAttrSize;
+ if ( fManMem )
+ p->pManMem = Extra_MmFixedStart( nAttrSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Start the attribute manager for integers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Attr_Man_t * Attr_ManStartInt( int nAttrs )
+{
+ Attr_Man_t * p;
+ p = Attr_ManAlloc( sizeof(int), 0 );
+ p->nAttrs = nAttrs;
+ p->pAttrs = (void **)ALLOC( int, nAttrs );
+ memset( (int *)p->pAttrs, 0, sizeof(int) * nAttrs );
+ p->fUseInt = 1;
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Start the attribute manager for pointers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Attr_Man_t * Attr_ManStartPtr( int nAttrs )
+{
+ Attr_Man_t * p;
+ p = Attr_ManAlloc( sizeof(void *), 0 );
+ p->nAttrs = nAttrs;
+ p->pAttrs = ALLOC( void *, nAttrs );
+ memset( p->pAttrs, 0, sizeof(void *) * nAttrs );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Start the attribute manager for the fixed entry size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Attr_Man_t * Attr_ManStartPtrMem( int nAttrs, int nAttrSize )
+{
+ Attr_Man_t * p;
+ int i;
+ p = Attr_ManAlloc( nAttrSize, 1 );
+ p->nAttrs = nAttrs;
+ p->pAttrs = ALLOC( void *, nAttrs );
+ for ( i = 0; i < p->nAttrs; i++ )
+ {
+ p->pAttrs[i] = Extra_MmFixedEntryFetch( p->pManMem );
+ memset( p->pAttrs[i], 0, nAttrSize );
+ }
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stop the attribute manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Attr_ManStop( Attr_Man_t * p )
+{
+ // free the attributes of objects
+ if ( p->pFuncFreeObj )
+ {
+ int i;
+ if ( p->fUseInt )
+ {
+ for ( i = 0; i < p->nAttrs; i++ )
+ if ( ((int *)p->pAttrs)[i] )
+ p->pFuncFreeObj( p->pManAttr, (void *)((int *)p->pAttrs)[i] );
+ }
+ else
+ {
+ for ( i = 0; i < p->nAttrs; i++ )
+ if ( p->pAttrs[i] )
+ p->pFuncFreeObj( p->pManAttr, p->pAttrs[i] );
+ }
+ }
+ // free the attribute manager
+ if ( p->pManAttr && p->pFuncFreeMan )
+ p->pFuncFreeMan( p->pManAttr );
+ // free the memory manager
+ if ( p->pManMem )
+ Extra_MmFixedStop( p->pManMem);
+ // free the attribute manager
+ FREE( p->pAttrs );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Attr_ManReadAttrInt( Attr_Man_t * p, int Id )
+{
+ assert( p->fUseInt );
+ if ( Id >= p->nAttrs )
+ return 0;
+ return ((int *)p->pAttrs)[Id];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void * Attr_ManReadAttrPtr( Attr_Man_t * p, int Id )
+{
+ assert( !p->fUseInt );
+ if ( Id >= p->nAttrs )
+ return NULL;
+ return p->pAttrs[Id];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Attr_ManWriteAttrInt( Attr_Man_t * p, int Id, int Attr )
+{
+ assert( p->fUseInt );
+ ((int *)p->pAttrs)[Id] = Attr;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Attr_ManWriteAttrPtr( Attr_Man_t * p, int Id, void * pAttr )
+{
+ assert( !p->fUseInt );
+ assert( p->pManMem == NULL );
+ p->pAttrs[Id] = pAttr;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns or creates the pointer to the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int * Attr_ManFetchSpotInt( Attr_Man_t * p, int Id )
+{
+ assert( p->fUseInt );
+ if ( Id >= p->nAttrs )
+ {
+ // save the old size
+ int i, nAttrsOld = p->nAttrs;
+ // get the new size
+ p->nAttrs = p->nAttrs? 2*p->nAttrs : 1024;
+ p->pAttrs = realloc( p->pAttrs, sizeof(int) * p->nAttrs );
+ // fill in the empty spots
+ for ( i = nAttrsOld; i < p->nAttrs; i++ )
+ ((int *)p->pAttrs)[Id] = 0;
+ }
+ return ((int *)p->pAttrs) + Id;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns or creates the pointer to the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void ** Attr_ManFetchSpotPtr( Attr_Man_t * p, int Id )
+{
+ assert( !p->fUseInt );
+ if ( Id >= p->nAttrs )
+ {
+ // save the old size
+ int i, nAttrsOld = p->nAttrs;
+ // get the new size
+ p->nAttrs = p->nAttrs? 2*p->nAttrs : 1024;
+ p->pAttrs = realloc( p->pAttrs, sizeof(void *) * p->nAttrs );
+ // fill in the empty spots
+ for ( i = nAttrsOld; i < p->nAttrs; i++ )
+ p->pAttrs[Id] = NULL;
+ }
+ // if memory manager is available but entry is not created, create it
+ if ( p->pManMem && p->pAttrs[Id] != NULL )
+ {
+ p->pAttrs[Id] = Extra_MmFixedEntryFetch( p->pManMem );
+ memset( p->pAttrs[Id], 0, p->nAttrSize );
+ }
+ return p->pAttrs + Id;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns or creates the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Attr_ManFetchAttrInt( Attr_Man_t * p, int Id )
+{
+ return *Attr_ManFetchSpotInt( p, Id );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns or creates the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void * Attr_ManFetchAttrPtr( Attr_Man_t * p, int Id )
+{
+ return *Attr_ManFetchSpotPtr( p, Id );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Attr_ManSetAttrInt( Attr_Man_t * p, int Id, int Attr )
+{
+ *Attr_ManFetchSpotInt( p, Id ) = Attr;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the attribute of the given object.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Attr_ManSetAttrPtr( Attr_Man_t * p, int Id, void * pAttr )
+{
+ assert( p->pManMem == NULL );
+ *Attr_ManFetchSpotPtr( p, Id ) = pAttr;
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/aig/ivy/ivy.h b/src/aig/ivy/ivy.h
new file mode 100644
index 00000000..c7435a63
--- /dev/null
+++ b/src/aig/ivy/ivy.h
@@ -0,0 +1,557 @@
+/**CFile****************************************************************
+
+ FileName [ivy.h]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [External declarations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivy.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#ifndef __IVY_H__
+#define __IVY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// INCLUDES ///
+////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "extra.h"
+#include "vec.h"
+
+////////////////////////////////////////////////////////////////////////
+/// PARAMETERS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// BASIC TYPES ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Ivy_Man_t_ Ivy_Man_t;
+typedef struct Ivy_Obj_t_ Ivy_Obj_t;
+typedef int Ivy_Edge_t;
+typedef struct Ivy_FraigParams_t_ Ivy_FraigParams_t;
+
+// object types
+typedef enum {
+ IVY_NONE, // 0: non-existent object
+ IVY_PI, // 1: primary input (and constant 1 node)
+ IVY_PO, // 2: primary output
+ IVY_ASSERT, // 3: assertion
+ IVY_LATCH, // 4: sequential element
+ IVY_AND, // 5: AND node
+ IVY_EXOR, // 6: EXOR node
+ IVY_BUF, // 7: buffer (temporary)
+ IVY_VOID // 8: unused object
+} Ivy_Type_t;
+
+// latch initial values
+typedef enum {
+ IVY_INIT_NONE, // 0: not a latch
+ IVY_INIT_0, // 1: zero
+ IVY_INIT_1, // 2: one
+ IVY_INIT_DC // 3: don't-care
+} Ivy_Init_t;
+
+// the AIG node
+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
+ unsigned Type : 4; // object type
+ unsigned fMarkA : 1; // multipurpose mask
+ unsigned fMarkB : 1; // multipurpose mask
+ unsigned fExFan : 1; // set to 1 if last fanout added is EXOR
+ unsigned fPhase : 1; // value under 000...0 pattern
+ unsigned fFailTfo : 1; // the TFO of the failed node
+ unsigned Init : 2; // latch initial value
+ unsigned Level : 21; // logic level
+ int nRefs; // reference counter
+ 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
+};
+
+// the AIG manager
+struct Ivy_Man_t_
+{
+ // AIG nodes
+ Vec_Ptr_t * vPis; // the array of PIs
+ Vec_Ptr_t * vPos; // the array of POs
+ Vec_Ptr_t * vBufs; // the array of buffers
+ Vec_Ptr_t * vObjs; // the array of objects
+ Ivy_Obj_t * pConst1; // the constant 1 node
+ Ivy_Obj_t Ghost; // the ghost node
+ // AIG node counters
+ int nObjs[IVY_VOID];// the number of objects by type
+ int nCreated; // the number of created objects
+ int nDeleted; // the number of deleted objects
+ // stuctural hash table
+ int * pTable; // structural hash table
+ int nTableSize; // structural hash table size
+ // various data members
+ int fCatchExor; // set to 1 to detect EXORs
+ int nTravIds; // the traversal ID
+ int nLevelMax; // the maximum level
+ Vec_Int_t * vRequired; // required times
+ int fFanout; // fanout is allocated
+ void * pData; // the temporary data
+ void * pCopy; // the temporary data
+ Ivy_Man_t * pHaig; // history AIG if present
+ int nClassesSkip; // the number of skipped classes
+ // memory management
+ Vec_Ptr_t * vChunks; // allocated memory pieces
+ Vec_Ptr_t * vPages; // memory pages used by nodes
+ Ivy_Obj_t * pListFree; // the list of free nodes
+ // timing statistics
+ int time1;
+ int time2;
+};
+
+struct Ivy_FraigParams_t_
+{
+ int nSimWords; // the number of words in the simulation info
+ double dSimSatur; // the ratio of refined classes when saturation is reached
+ int fPatScores; // enables simulation pattern scoring
+ int MaxScore; // max score after which resimulation is used
+ double dActConeRatio; // the ratio of cone to be bumped
+ double dActConeBumpMax; // the largest bump in activity
+ int fProve; // prove the miter outputs
+ int fVerbose; // verbose output
+ int fDoSparse; // skip sparse functions
+ int nBTLimitNode; // conflict limit at a node
+ int nBTLimitMiter; // conflict limit at an output
+// int nBTLimitGlobal; // conflict limit global
+// int nInsLimitNode; // inspection limit at a node
+// int nInsLimitMiter; // inspection limit at an output
+// int nInsLimitGlobal; // inspection limit global
+};
+
+
+#define IVY_CUT_LIMIT 256
+#define IVY_CUT_INPUT 6
+
+typedef struct Ivy_Cut_t_ Ivy_Cut_t;
+struct Ivy_Cut_t_
+{
+ int nLatches;
+ short nSize;
+ short nSizeMax;
+ int pArray[IVY_CUT_INPUT];
+ unsigned uHash;
+};
+
+typedef struct Ivy_Store_t_ Ivy_Store_t;
+struct Ivy_Store_t_
+{
+ int nCuts;
+ int nCutsM;
+ int nCutsMax;
+ int fSatur;
+ Ivy_Cut_t pCuts[IVY_CUT_LIMIT]; // storage for cuts
+};
+
+#define IVY_LEAF_MASK 255
+#define IVY_LEAF_BITS 8
+
+////////////////////////////////////////////////////////////////////////
+/// MACRO DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define IVY_MIN(a,b) (((a) < (b))? (a) : (b))
+#define IVY_MAX(a,b) (((a) > (b))? (a) : (b))
+
+static inline int Ivy_BitWordNum( int nBits ) { return (nBits>>5) + ((nBits&31) > 0); }
+static inline int Ivy_TruthWordNum( int nVars ) { return nVars <= 5 ? 1 : (1 << (nVars - 5)); }
+static inline int Ivy_InfoHasBit( unsigned * p, int i ) { return (p[(i)>>5] & (1<<((i) & 31))) > 0; }
+static inline void Ivy_InfoSetBit( unsigned * p, int i ) { p[(i)>>5] |= (1<<((i) & 31)); }
+static inline void Ivy_InfoXorBit( unsigned * p, int i ) { p[(i)>>5] ^= (1<<((i) & 31)); }
+
+static inline Ivy_Obj_t * Ivy_Regular( Ivy_Obj_t * p ) { return (Ivy_Obj_t *)((unsigned long)(p) & ~01); }
+static inline Ivy_Obj_t * Ivy_Not( Ivy_Obj_t * p ) { return (Ivy_Obj_t *)((unsigned long)(p) ^ 01); }
+static inline Ivy_Obj_t * Ivy_NotCond( Ivy_Obj_t * p, int c ) { return (Ivy_Obj_t *)((unsigned long)(p) ^ (c)); }
+static inline int Ivy_IsComplement( Ivy_Obj_t * p ) { return (int)((unsigned long)(p) & 01); }
+
+static inline Ivy_Obj_t * Ivy_ManConst0( Ivy_Man_t * p ) { return Ivy_Not(p->pConst1); }
+static inline Ivy_Obj_t * Ivy_ManConst1( Ivy_Man_t * p ) { return p->pConst1; }
+static inline Ivy_Obj_t * Ivy_ManGhost( Ivy_Man_t * p ) { return &p->Ghost; }
+static inline Ivy_Obj_t * Ivy_ManPi( Ivy_Man_t * p, int i ) { return (Ivy_Obj_t *)Vec_PtrEntry(p->vPis, i); }
+static inline Ivy_Obj_t * Ivy_ManPo( Ivy_Man_t * p, int i ) { return (Ivy_Obj_t *)Vec_PtrEntry(p->vPos, i); }
+static inline Ivy_Obj_t * Ivy_ManObj( Ivy_Man_t * p, int i ) { return (Ivy_Obj_t *)Vec_PtrEntry(p->vObjs, i); }
+
+static inline Ivy_Edge_t Ivy_EdgeCreate( int Id, int fCompl ) { return (Id << 1) | fCompl; }
+static inline int Ivy_EdgeId( Ivy_Edge_t Edge ) { return Edge >> 1; }
+static inline int Ivy_EdgeIsComplement( Ivy_Edge_t Edge ) { return Edge & 1; }
+static inline Ivy_Edge_t Ivy_EdgeRegular( Ivy_Edge_t Edge ) { return (Edge >> 1) << 1; }
+static inline Ivy_Edge_t Ivy_EdgeNot( Ivy_Edge_t Edge ) { return Edge ^ 1; }
+static inline Ivy_Edge_t Ivy_EdgeNotCond( Ivy_Edge_t Edge, int fCond ) { return Edge ^ fCond; }
+static inline Ivy_Edge_t Ivy_EdgeFromNode( Ivy_Obj_t * pNode ) { return Ivy_EdgeCreate( Ivy_Regular(pNode)->Id, Ivy_IsComplement(pNode) ); }
+static inline Ivy_Obj_t * Ivy_EdgeToNode( Ivy_Man_t * p, Ivy_Edge_t Edge ){ return Ivy_NotCond( Ivy_ManObj(p, Ivy_EdgeId(Edge)), Ivy_EdgeIsComplement(Edge) ); }
+
+static inline int Ivy_LeafCreate( int Id, int Lat ) { return (Id << IVY_LEAF_BITS) | Lat; }
+static inline int Ivy_LeafId( int Leaf ) { return Leaf >> IVY_LEAF_BITS; }
+static inline int Ivy_LeafLat( int Leaf ) { return Leaf & IVY_LEAF_MASK; }
+
+static inline int Ivy_ManPiNum( Ivy_Man_t * p ) { return p->nObjs[IVY_PI]; }
+static inline int Ivy_ManPoNum( Ivy_Man_t * p ) { return p->nObjs[IVY_PO]; }
+static inline int Ivy_ManAssertNum( Ivy_Man_t * p ) { return p->nObjs[IVY_ASSERT]; }
+static inline int Ivy_ManLatchNum( Ivy_Man_t * p ) { return p->nObjs[IVY_LATCH]; }
+static inline int Ivy_ManAndNum( Ivy_Man_t * p ) { return p->nObjs[IVY_AND]; }
+static inline int Ivy_ManExorNum( Ivy_Man_t * p ) { return p->nObjs[IVY_EXOR]; }
+static inline int Ivy_ManBufNum( Ivy_Man_t * p ) { return p->nObjs[IVY_BUF]; }
+static inline int Ivy_ManObjNum( Ivy_Man_t * p ) { return p->nCreated - p->nDeleted; }
+static inline int Ivy_ManObjIdMax( Ivy_Man_t * p ) { return Vec_PtrSize(p->vObjs)-1; }
+static inline int Ivy_ManNodeNum( Ivy_Man_t * p ) { return p->nObjs[IVY_AND]+p->nObjs[IVY_EXOR];}
+static inline int Ivy_ManHashObjNum( Ivy_Man_t * p ) { return p->nObjs[IVY_AND]+p->nObjs[IVY_EXOR]+p->nObjs[IVY_LATCH]; }
+static inline int Ivy_ManGetCost( Ivy_Man_t * p ) { return p->nObjs[IVY_AND]+3*p->nObjs[IVY_EXOR]+8*p->nObjs[IVY_LATCH]; }
+
+static inline Ivy_Type_t Ivy_ObjType( Ivy_Obj_t * pObj ) { return pObj->Type; }
+static inline Ivy_Init_t Ivy_ObjInit( Ivy_Obj_t * pObj ) { return pObj->Init; }
+static inline int Ivy_ObjIsConst1( Ivy_Obj_t * pObj ) { return pObj->Id == 0; }
+static inline int Ivy_ObjIsGhost( Ivy_Obj_t * pObj ) { return pObj->Id < 0; }
+static inline int Ivy_ObjIsNone( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_NONE; }
+static inline int Ivy_ObjIsPi( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_PI; }
+static inline int Ivy_ObjIsPo( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_PO; }
+static inline int Ivy_ObjIsCi( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_PI || pObj->Type == IVY_LATCH; }
+static inline int Ivy_ObjIsCo( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_PO || pObj->Type == IVY_LATCH; }
+static inline int Ivy_ObjIsAssert( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_ASSERT; }
+static inline int Ivy_ObjIsLatch( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_LATCH; }
+static inline int Ivy_ObjIsAnd( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_AND; }
+static inline int Ivy_ObjIsExor( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_EXOR; }
+static inline int Ivy_ObjIsBuf( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_BUF; }
+static inline int Ivy_ObjIsNode( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_AND || pObj->Type == IVY_EXOR; }
+static inline int Ivy_ObjIsTerm( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_PI || pObj->Type == IVY_PO || pObj->Type == IVY_ASSERT; }
+static inline int Ivy_ObjIsHash( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_AND || pObj->Type == IVY_EXOR || pObj->Type == IVY_LATCH; }
+static inline int Ivy_ObjIsOneFanin( Ivy_Obj_t * pObj ) { return pObj->Type == IVY_PO || pObj->Type == IVY_ASSERT || pObj->Type == IVY_BUF || pObj->Type == IVY_LATCH; }
+
+static inline int Ivy_ObjIsMarkA( Ivy_Obj_t * pObj ) { return pObj->fMarkA; }
+static inline void Ivy_ObjSetMarkA( Ivy_Obj_t * pObj ) { pObj->fMarkA = 1; }
+static inline void Ivy_ObjClearMarkA( Ivy_Obj_t * pObj ) { pObj->fMarkA = 0; }
+
+static inline void Ivy_ObjSetTravId( Ivy_Obj_t * pObj, int TravId ) { pObj->TravId = TravId; }
+static inline void Ivy_ObjSetTravIdCurrent( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { pObj->TravId = p->nTravIds; }
+static inline void Ivy_ObjSetTravIdPrevious( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { pObj->TravId = p->nTravIds - 1; }
+static inline int Ivy_ObjIsTravIdCurrent( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { return (int )((int)pObj->TravId == p->nTravIds); }
+static inline int Ivy_ObjIsTravIdPrevious( Ivy_Man_t * p, Ivy_Obj_t * pObj ) { return (int )((int)pObj->TravId == p->nTravIds - 1); }
+
+static inline int Ivy_ObjId( Ivy_Obj_t * pObj ) { return pObj->Id; }
+static inline int Ivy_ObjTravId( Ivy_Obj_t * pObj ) { return pObj->TravId; }
+static inline int Ivy_ObjPhase( Ivy_Obj_t * pObj ) { return pObj->fPhase; }
+static inline int Ivy_ObjExorFanout( Ivy_Obj_t * pObj ) { return pObj->fExFan; }
+static inline int Ivy_ObjRefs( Ivy_Obj_t * pObj ) { return pObj->nRefs; }
+static inline void Ivy_ObjRefsInc( Ivy_Obj_t * pObj ) { pObj->nRefs++; }
+static inline void Ivy_ObjRefsDec( Ivy_Obj_t * pObj ) { assert( pObj->nRefs > 0 ); pObj->nRefs--; }
+static inline int Ivy_ObjFaninId0( Ivy_Obj_t * pObj ) { return pObj->pFanin0? Ivy_ObjId(Ivy_Regular(pObj->pFanin0)) : 0; }
+static inline int Ivy_ObjFaninId1( Ivy_Obj_t * pObj ) { return pObj->pFanin1? Ivy_ObjId(Ivy_Regular(pObj->pFanin1)) : 0; }
+static inline int Ivy_ObjFaninC0( Ivy_Obj_t * pObj ) { return Ivy_IsComplement(pObj->pFanin0); }
+static inline int Ivy_ObjFaninC1( Ivy_Obj_t * pObj ) { return Ivy_IsComplement(pObj->pFanin1); }
+static inline Ivy_Obj_t * Ivy_ObjFanin0( Ivy_Obj_t * pObj ) { return Ivy_Regular(pObj->pFanin0); }
+static inline Ivy_Obj_t * Ivy_ObjFanin1( Ivy_Obj_t * pObj ) { return Ivy_Regular(pObj->pFanin1); }
+static inline Ivy_Obj_t * Ivy_ObjChild0( Ivy_Obj_t * pObj ) { return pObj->pFanin0; }
+static inline Ivy_Obj_t * Ivy_ObjChild1( Ivy_Obj_t * pObj ) { return pObj->pFanin1; }
+static inline Ivy_Obj_t * Ivy_ObjChild0Equiv( Ivy_Obj_t * pObj ) { assert( !Ivy_IsComplement(pObj) ); return Ivy_ObjFanin0(pObj)? Ivy_NotCond(Ivy_ObjFanin0(pObj)->pEquiv, Ivy_ObjFaninC0(pObj)) : NULL; }
+static inline Ivy_Obj_t * Ivy_ObjChild1Equiv( Ivy_Obj_t * pObj ) { assert( !Ivy_IsComplement(pObj) ); return Ivy_ObjFanin1(pObj)? Ivy_NotCond(Ivy_ObjFanin1(pObj)->pEquiv, Ivy_ObjFaninC1(pObj)) : NULL; }
+static inline Ivy_Obj_t * Ivy_ObjEquiv( Ivy_Obj_t * pObj ) { return Ivy_Regular(pObj)->pEquiv? Ivy_NotCond(Ivy_Regular(pObj)->pEquiv, Ivy_IsComplement(pObj)) : NULL; }
+static inline int Ivy_ObjLevel( Ivy_Obj_t * pObj ) { return pObj->Level; }
+static inline int Ivy_ObjLevelNew( Ivy_Obj_t * pObj ) { return 1 + Ivy_ObjIsExor(pObj) + IVY_MAX(Ivy_ObjFanin0(pObj)->Level, Ivy_ObjFanin1(pObj)->Level); }
+static inline int Ivy_ObjFaninPhase( Ivy_Obj_t * pObj ) { return Ivy_IsComplement(pObj)? !Ivy_Regular(pObj)->fPhase : pObj->fPhase; }
+
+static inline void Ivy_ObjClean( Ivy_Obj_t * pObj )
+{
+ int IdSaved = pObj->Id;
+ memset( pObj, 0, sizeof(Ivy_Obj_t) );
+ pObj->Id = IdSaved;
+}
+static inline void Ivy_ObjOverwrite( Ivy_Obj_t * pBase, Ivy_Obj_t * pData )
+{
+ int IdSaved = pBase->Id;
+ memcpy( pBase, pData, sizeof(Ivy_Obj_t) );
+ pBase->Id = IdSaved;
+}
+static inline int Ivy_ObjWhatFanin( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanin )
+{
+ if ( Ivy_ObjFanin0(pObj) == pFanin ) return 0;
+ if ( Ivy_ObjFanin1(pObj) == pFanin ) return 1;
+ assert(0); return -1;
+}
+static inline int Ivy_ObjFanoutC( Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout )
+{
+ if ( Ivy_ObjFanin0(pFanout) == pObj ) return Ivy_ObjFaninC0(pObj);
+ if ( Ivy_ObjFanin1(pFanout) == pObj ) return Ivy_ObjFaninC1(pObj);
+ assert(0); return -1;
+}
+
+// create the ghost of the new node
+static inline Ivy_Obj_t * Ivy_ObjCreateGhost( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1, Ivy_Type_t Type, Ivy_Init_t Init )
+{
+ Ivy_Obj_t * pGhost, * pTemp;
+ assert( Type != IVY_AND || !Ivy_ObjIsConst1(Ivy_Regular(p0)) );
+ assert( p1 == NULL || !Ivy_ObjIsConst1(Ivy_Regular(p1)) );
+ assert( Type == IVY_PI || Ivy_Regular(p0) != Ivy_Regular(p1) );
+ assert( Type != IVY_LATCH || !Ivy_IsComplement(p0) );
+// assert( p1 == NULL || (!Ivy_ObjIsLatch(Ivy_Regular(p0)) || !Ivy_ObjIsLatch(Ivy_Regular(p1))) );
+ pGhost = Ivy_ManGhost(p);
+ pGhost->Type = Type;
+ pGhost->Init = Init;
+ pGhost->pFanin0 = p0;
+ pGhost->pFanin1 = p1;
+ if ( p1 && Ivy_ObjFaninId0(pGhost) > Ivy_ObjFaninId1(pGhost) )
+ pTemp = pGhost->pFanin0, pGhost->pFanin0 = pGhost->pFanin1, pGhost->pFanin1 = pTemp;
+ return pGhost;
+}
+
+// get the complemented initial state
+static Ivy_Init_t Ivy_InitNotCond( Ivy_Init_t Init, int fCompl )
+{
+ assert( Init != IVY_INIT_NONE );
+ if ( fCompl == 0 )
+ return Init;
+ if ( Init == IVY_INIT_0 )
+ return IVY_INIT_1;
+ if ( Init == IVY_INIT_1 )
+ return IVY_INIT_0;
+ return IVY_INIT_DC;
+}
+
+// get the initial state after forward retiming over AND gate
+static Ivy_Init_t Ivy_InitAnd( Ivy_Init_t InitA, Ivy_Init_t InitB )
+{
+ assert( InitA != IVY_INIT_NONE && InitB != IVY_INIT_NONE );
+ if ( InitA == IVY_INIT_0 || InitB == IVY_INIT_0 )
+ return IVY_INIT_0;
+ if ( InitA == IVY_INIT_DC || InitB == IVY_INIT_DC )
+ return IVY_INIT_DC;
+ return IVY_INIT_1;
+}
+
+// get the initial state after forward retiming over EXOR gate
+static Ivy_Init_t Ivy_InitExor( Ivy_Init_t InitA, Ivy_Init_t InitB )
+{
+ assert( InitA != IVY_INIT_NONE && InitB != IVY_INIT_NONE );
+ if ( InitA == IVY_INIT_DC || InitB == IVY_INIT_DC )
+ return IVY_INIT_DC;
+ if ( InitA == IVY_INIT_0 && InitB == IVY_INIT_1 )
+ return IVY_INIT_1;
+ if ( InitA == IVY_INIT_1 && InitB == IVY_INIT_0 )
+ return IVY_INIT_1;
+ return IVY_INIT_0;
+}
+
+// internal memory manager
+static inline Ivy_Obj_t * Ivy_ManFetchMemory( Ivy_Man_t * p )
+{
+ extern void Ivy_ManAddMemory( Ivy_Man_t * p );
+ Ivy_Obj_t * pTemp;
+ if ( p->pListFree == NULL )
+ Ivy_ManAddMemory( p );
+ pTemp = p->pListFree;
+ p->pListFree = *((Ivy_Obj_t **)pTemp);
+ memset( pTemp, 0, sizeof(Ivy_Obj_t) );
+ return pTemp;
+}
+static inline void Ivy_ManRecycleMemory( Ivy_Man_t * p, Ivy_Obj_t * pEntry )
+{
+ pEntry->Type = IVY_NONE; // distinquishes dead node from live node
+ *((Ivy_Obj_t **)pEntry) = p->pListFree;
+ p->pListFree = pEntry;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// ITERATORS ///
+////////////////////////////////////////////////////////////////////////
+
+// iterator over the primary inputs
+#define Ivy_ManForEachPi( p, pObj, i ) \
+ Vec_PtrForEachEntry( p->vPis, pObj, i )
+// iterator over the primary outputs
+#define Ivy_ManForEachPo( p, pObj, i ) \
+ Vec_PtrForEachEntry( p->vPos, pObj, i )
+// iterator over all objects, including those currently not used
+#define Ivy_ManForEachObj( p, pObj, i ) \
+ Vec_PtrForEachEntry( p->vObjs, pObj, i ) if ( (pObj) == NULL ) {} else
+// iterator over the combinational inputs
+#define Ivy_ManForEachCi( p, pObj, i ) \
+ Ivy_ManForEachObj( p, pObj, i ) if ( !Ivy_ObjIsCi(pObj) ) {} else
+// iterator over the combinational outputs
+#define Ivy_ManForEachCo( p, pObj, i ) \
+ Ivy_ManForEachObj( p, pObj, i ) if ( !Ivy_ObjIsCo(pObj) ) {} else
+// iterator over logic nodes (AND and EXOR gates)
+#define Ivy_ManForEachNode( p, pObj, i ) \
+ Ivy_ManForEachObj( p, pObj, i ) if ( !Ivy_ObjIsNode(pObj) ) {} else
+// iterator over logic latches
+#define Ivy_ManForEachLatch( p, pObj, i ) \
+ Ivy_ManForEachObj( p, pObj, i ) if ( !Ivy_ObjIsLatch(pObj) ) {} else
+// iterator over the nodes whose IDs are stored in the array
+#define Ivy_ManForEachNodeVec( p, vIds, pObj, i ) \
+ for ( i = 0; i < Vec_IntSize(vIds) && ((pObj) = Ivy_ManObj(p, Vec_IntEntry(vIds,i))); i++ )
+// iterator over the fanouts of an object
+#define Ivy_ObjForEachFanout( p, pObj, vArray, pFanout, i ) \
+ for ( i = 0, Ivy_ObjCollectFanouts(p, pObj, vArray); \
+ i < Vec_PtrSize(vArray) && ((pFanout) = Vec_PtrEntry(vArray,i)); i++ )
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*=== ivyBalance.c ========================================================*/
+extern Ivy_Man_t * Ivy_ManBalance( Ivy_Man_t * p, int fUpdateLevel );
+extern Ivy_Obj_t * Ivy_NodeBalanceBuildSuper( Ivy_Man_t * p, Vec_Ptr_t * vSuper, Ivy_Type_t Type, int fUpdateLevel );
+/*=== ivyCanon.c ========================================================*/
+extern Ivy_Obj_t * Ivy_CanonAnd( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 );
+extern Ivy_Obj_t * Ivy_CanonExor( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 );
+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_ManCheckFanoutNums( Ivy_Man_t * p );
+extern int Ivy_ManCheckFanouts( Ivy_Man_t * p );
+extern int Ivy_ManCheckChoices( 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 );
+/*=== ivyDfs.c ==========================================================*/
+extern Vec_Int_t * Ivy_ManDfs( Ivy_Man_t * p );
+extern Vec_Int_t * Ivy_ManDfsSeq( Ivy_Man_t * p, Vec_Int_t ** pvLatches );
+extern void Ivy_ManCollectCone( Ivy_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vCone );
+extern Vec_Vec_t * Ivy_ManLevelize( Ivy_Man_t * p );
+extern Vec_Int_t * Ivy_ManRequiredLevels( Ivy_Man_t * p );
+extern int Ivy_ManIsAcyclic( Ivy_Man_t * p );
+extern int Ivy_ManSetLevels( Ivy_Man_t * p, int fHaig );
+/*=== ivyDsd.c ==========================================================*/
+extern int Ivy_TruthDsd( unsigned uTruth, Vec_Int_t * vTree );
+extern void Ivy_TruthDsdPrint( FILE * pFile, Vec_Int_t * vTree );
+extern unsigned Ivy_TruthDsdCompute( Vec_Int_t * vTree );
+extern void Ivy_TruthDsdComputePrint( unsigned uTruth );
+extern Ivy_Obj_t * Ivy_ManDsdConstruct( Ivy_Man_t * p, Vec_Int_t * vFront, Vec_Int_t * vTree );
+/*=== ivyFanout.c ==========================================================*/
+extern void Ivy_ManStartFanout( Ivy_Man_t * p );
+extern void Ivy_ManStopFanout( Ivy_Man_t * p );
+extern void Ivy_ObjAddFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFanout );
+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_ObjReadFirstFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern int Ivy_ObjFanoutNum( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+/*=== ivyFastMap.c =============================================================*/
+extern void Ivy_FastMapPerform( Ivy_Man_t * pAig, int nLimit, int fRecovery, int fVerbose );
+extern void Ivy_FastMapStop( Ivy_Man_t * pAig );
+extern void Ivy_FastMapReadSupp( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Vec_Int_t * vLeaves );
+extern void Ivy_FastMapReverseLevel( Ivy_Man_t * pAig );
+/*=== ivyFraig.c ==========================================================*/
+extern int Ivy_FraigProve( Ivy_Man_t ** ppManAig, void * pPars );
+extern Ivy_Man_t * Ivy_FraigPerform( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams );
+extern Ivy_Man_t * Ivy_FraigMiter( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams );
+extern void Ivy_FraigParamsDefault( Ivy_FraigParams_t * pParams );
+/*=== ivyHaig.c ==========================================================*/
+extern void Ivy_ManHaigStart( Ivy_Man_t * p, int fVerbose );
+extern void Ivy_ManHaigTrasfer( Ivy_Man_t * p, Ivy_Man_t * pNew );
+extern void Ivy_ManHaigStop( Ivy_Man_t * p );
+extern void Ivy_ManHaigPostprocess( Ivy_Man_t * p, int fVerbose );
+extern void Ivy_ManHaigCreateObj( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_ManHaigCreateChoice( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew );
+extern void Ivy_ManHaigSimulate( Ivy_Man_t * p );
+/*=== ivyMan.c ==========================================================*/
+extern Ivy_Man_t * Ivy_ManStart();
+extern Ivy_Man_t * Ivy_ManStartFrom( Ivy_Man_t * p );
+extern Ivy_Man_t * Ivy_ManDup( Ivy_Man_t * p );
+extern Ivy_Man_t * Ivy_ManFrames( Ivy_Man_t * pMan, int nLatches, int nFrames, int fInit, Vec_Ptr_t ** pvMapping );
+extern void Ivy_ManStop( Ivy_Man_t * p );
+extern int Ivy_ManCleanup( Ivy_Man_t * p );
+extern int Ivy_ManPropagateBuffers( Ivy_Man_t * p, int fUpdateLevel );
+extern void Ivy_ManPrintStats( Ivy_Man_t * p );
+extern void Ivy_ManMakeSeq( Ivy_Man_t * p, int nLatches, int * pInits );
+/*=== ivyMem.c ==========================================================*/
+extern void Ivy_ManStartMemory( Ivy_Man_t * p );
+extern void Ivy_ManStopMemory( Ivy_Man_t * p );
+/*=== ivyMulti.c ==========================================================*/
+extern Ivy_Obj_t * Ivy_Multi( Ivy_Man_t * p, Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type );
+extern Ivy_Obj_t * Ivy_Multi1( Ivy_Man_t * p, Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type );
+extern Ivy_Obj_t * Ivy_Multi_rec( Ivy_Man_t * p, Ivy_Obj_t ** ppObjs, int nObjs, Ivy_Type_t Type );
+extern Ivy_Obj_t * Ivy_MultiBalance_rec( Ivy_Man_t * p, Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type );
+extern int Ivy_MultiPlus( Ivy_Man_t * p, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Ivy_Type_t Type, int nLimit, Vec_Ptr_t * vSol );
+/*=== ivyObj.c ==========================================================*/
+extern Ivy_Obj_t * Ivy_ObjCreatePi( Ivy_Man_t * p );
+extern Ivy_Obj_t * Ivy_ObjCreatePo( Ivy_Man_t * p, Ivy_Obj_t * pDriver );
+extern Ivy_Obj_t * Ivy_ObjCreate( Ivy_Man_t * p, Ivy_Obj_t * pGhost );
+extern void Ivy_ObjConnect( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFan0, Ivy_Obj_t * pFan1 );
+extern void Ivy_ObjDisconnect( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_ObjPatchFanin0( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFaninNew );
+extern void Ivy_ObjDelete( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fFreeTop );
+extern void Ivy_ObjDelete_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fFreeTop );
+extern void Ivy_ObjReplace( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew, int fDeleteOld, int fFreeTop, int fUpdateLevel );
+extern void Ivy_NodeFixBufferFanins( Ivy_Man_t * p, Ivy_Obj_t * pNode, int fUpdateLevel );
+/*=== ivyOper.c =========================================================*/
+extern Ivy_Obj_t * Ivy_Oper( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1, Ivy_Type_t Type );
+extern Ivy_Obj_t * Ivy_And( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 );
+extern Ivy_Obj_t * Ivy_Or( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 );
+extern Ivy_Obj_t * Ivy_Exor( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 );
+extern Ivy_Obj_t * Ivy_Mux( Ivy_Man_t * p, Ivy_Obj_t * pC, Ivy_Obj_t * p1, Ivy_Obj_t * p0 );
+extern Ivy_Obj_t * Ivy_Maj( Ivy_Man_t * p, Ivy_Obj_t * pA, Ivy_Obj_t * pB, Ivy_Obj_t * pC );
+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 );
+extern Ivy_Man_t * Ivy_ManRwsat( Ivy_Man_t * pMan, int fVerbose );
+/*=== ivyRewrite.c =========================================================*/
+extern int Ivy_ManSeqRewrite( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost );
+extern int Ivy_ManRewriteAlg( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost );
+extern int Ivy_ManRewritePre( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost, int fVerbose );
+/*=== ivySeq.c =========================================================*/
+extern int Ivy_ManRewriteSeq( Ivy_Man_t * p, int fUseZeroCost, int fVerbose );
+/*=== ivyShow.c =========================================================*/
+extern void Ivy_ManShow( Ivy_Man_t * pMan, int fHaig, Vec_Ptr_t * vBold );
+/*=== ivyTable.c ========================================================*/
+extern Ivy_Obj_t * Ivy_TableLookup( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_TableInsert( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_TableDelete( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_TableUpdate( Ivy_Man_t * p, Ivy_Obj_t * pObj, int ObjIdNew );
+extern int Ivy_TableCountEntries( Ivy_Man_t * p );
+extern void Ivy_TableProfile( Ivy_Man_t * p );
+/*=== ivyUtil.c =========================================================*/
+extern void Ivy_ManIncrementTravId( Ivy_Man_t * p );
+extern void Ivy_ManCleanTravId( Ivy_Man_t * p );
+extern unsigned * Ivy_ManCutTruth( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Int_t * vLeaves, Vec_Int_t * vNodes, Vec_Int_t * vTruth );
+extern void Ivy_ManCollectCut( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Int_t * vLeaves, Vec_Int_t * vNodes );
+extern Vec_Int_t * Ivy_ManLatches( Ivy_Man_t * p );
+extern int Ivy_ManLevels( Ivy_Man_t * p );
+extern void Ivy_ManResetLevels( Ivy_Man_t * p );
+extern int Ivy_ObjMffcLabel( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_ObjUpdateLevel_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj );
+extern void Ivy_ObjUpdateLevelR_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, int ReqNew );
+extern int Ivy_ObjIsMuxType( Ivy_Obj_t * pObj );
+extern Ivy_Obj_t * Ivy_ObjRecognizeMux( Ivy_Obj_t * pObj, Ivy_Obj_t ** ppObjT, Ivy_Obj_t ** ppObjE );
+extern Ivy_Obj_t * Ivy_ObjReal( Ivy_Obj_t * pObj );
+extern void Ivy_ObjPrintVerbose( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fHaig );
+extern void Ivy_ManPrintVerbose( Ivy_Man_t * p, int fHaig );
+extern int Ivy_CutTruthPrint( Ivy_Man_t * p, Ivy_Cut_t * pCut, unsigned uTruth );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
diff --git a/src/aig/ivy/ivyBalance.c b/src/aig/ivy/ivyBalance.c
new file mode 100644
index 00000000..5627039a
--- /dev/null
+++ b/src/aig/ivy/ivyBalance.c
@@ -0,0 +1,404 @@
+/**CFile****************************************************************
+
+ FileName [ivyBalance.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Algebraic AIG balancing.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyBalance.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Ivy_NodeBalance_rec( Ivy_Man_t * pNew, Ivy_Obj_t * pObj, Vec_Vec_t * vStore, int Level, int fUpdateLevel );
+static Vec_Ptr_t * Ivy_NodeBalanceCone( Ivy_Obj_t * pObj, Vec_Vec_t * vStore, int Level );
+static int Ivy_NodeBalanceFindLeft( Vec_Ptr_t * vSuper );
+static void Ivy_NodeBalancePermute( Ivy_Man_t * p, Vec_Ptr_t * vSuper, int LeftBound, int fExor );
+static void Ivy_NodeBalancePushUniqueOrderByLevel( Vec_Ptr_t * vStore, Ivy_Obj_t * pObj );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs algebraic balancing of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManBalance( Ivy_Man_t * p, int fUpdateLevel )
+{
+ Ivy_Man_t * pNew;
+ Ivy_Obj_t * pObj, * pDriver;
+ Vec_Vec_t * vStore;
+ int i, NewNodeId;
+ // clean the old manager
+ Ivy_ManCleanTravId( p );
+ // create the new manager
+ pNew = Ivy_ManStart();
+ // map the nodes
+ Ivy_ManConst1(p)->TravId = Ivy_EdgeFromNode( Ivy_ManConst1(pNew) );
+ Ivy_ManForEachPi( p, pObj, i )
+ pObj->TravId = Ivy_EdgeFromNode( Ivy_ObjCreatePi(pNew) );
+ // if HAIG is defined, trasfer the pointers to the PIs/latches
+// if ( p->pHaig )
+// Ivy_ManHaigTrasfer( p, pNew );
+ // balance the AIG
+ vStore = Vec_VecAlloc( 50 );
+ Ivy_ManForEachPo( p, pObj, i )
+ {
+ pDriver = Ivy_ObjReal( Ivy_ObjChild0(pObj) );
+ NewNodeId = Ivy_NodeBalance_rec( pNew, Ivy_Regular(pDriver), vStore, 0, fUpdateLevel );
+ NewNodeId = Ivy_EdgeNotCond( NewNodeId, Ivy_IsComplement(pDriver) );
+ Ivy_ObjCreatePo( pNew, Ivy_EdgeToNode(pNew, NewNodeId) );
+ }
+ Vec_VecFree( vStore );
+ if ( i = Ivy_ManCleanup( pNew ) )
+ {
+// printf( "Cleanup after balancing removed %d dangling nodes.\n", i );
+ }
+ // check the resulting AIG
+ if ( !Ivy_ManCheck(pNew) )
+ printf( "Ivy_ManBalance(): The check has failed.\n" );
+ return pNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Procedure used for sorting the nodes in decreasing order of levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeCompareLevelsDecrease( Ivy_Obj_t ** pp1, Ivy_Obj_t ** pp2 )
+{
+ int Diff = Ivy_Regular(*pp1)->Level - Ivy_Regular(*pp2)->Level;
+ if ( Diff > 0 )
+ return -1;
+ if ( Diff < 0 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the ID of new node constructed.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeBalance_rec( Ivy_Man_t * pNew, Ivy_Obj_t * pObjOld, Vec_Vec_t * vStore, int Level, int fUpdateLevel )
+{
+ Ivy_Obj_t * pObjNew;
+ Vec_Ptr_t * vSuper;
+ int i, NewNodeId;
+ assert( !Ivy_IsComplement(pObjOld) );
+ assert( !Ivy_ObjIsBuf(pObjOld) );
+ // return if the result is known
+ if ( Ivy_ObjIsConst1(pObjOld) )
+ return pObjOld->TravId;
+ if ( pObjOld->TravId )
+ return pObjOld->TravId;
+ assert( Ivy_ObjIsNode(pObjOld) );
+ // get the implication supergate
+ vSuper = Ivy_NodeBalanceCone( pObjOld, vStore, Level );
+ if ( vSuper->nSize == 0 )
+ { // it means that the supergate contains two nodes in the opposite polarity
+ pObjOld->TravId = Ivy_EdgeFromNode( Ivy_ManConst0(pNew) );
+ return pObjOld->TravId;
+ }
+ if ( vSuper->nSize < 2 )
+ printf( "BUG!\n" );
+ // for each old node, derive the new well-balanced node
+ for ( i = 0; i < vSuper->nSize; i++ )
+ {
+ NewNodeId = Ivy_NodeBalance_rec( pNew, Ivy_Regular(vSuper->pArray[i]), vStore, Level + 1, fUpdateLevel );
+ NewNodeId = Ivy_EdgeNotCond( NewNodeId, Ivy_IsComplement(vSuper->pArray[i]) );
+ vSuper->pArray[i] = Ivy_EdgeToNode( pNew, NewNodeId );
+ }
+ // build the supergate
+ pObjNew = Ivy_NodeBalanceBuildSuper( pNew, vSuper, Ivy_ObjType(pObjOld), fUpdateLevel );
+ vSuper->nSize = 0;
+ // make sure the balanced node is not assigned
+ assert( pObjOld->TravId == 0 );
+ pObjOld->TravId = Ivy_EdgeFromNode( pObjNew );
+// assert( pObjOld->Level >= Ivy_Regular(pObjNew)->Level );
+ return pObjOld->TravId;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Builds implication supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_NodeBalanceBuildSuper( Ivy_Man_t * p, Vec_Ptr_t * vSuper, Ivy_Type_t Type, int fUpdateLevel )
+{
+ Ivy_Obj_t * pObj1, * pObj2;
+ int LeftBound;
+ assert( vSuper->nSize > 1 );
+ // sort the new nodes by level in the decreasing order
+ Vec_PtrSort( vSuper, Ivy_NodeCompareLevelsDecrease );
+ // balance the nodes
+ while ( vSuper->nSize > 1 )
+ {
+ // find the left bound on the node to be paired
+ LeftBound = (!fUpdateLevel)? 0 : Ivy_NodeBalanceFindLeft( vSuper );
+ // find the node that can be shared (if no such node, randomize choice)
+ Ivy_NodeBalancePermute( p, vSuper, LeftBound, Type == IVY_EXOR );
+ // pull out the last two nodes
+ pObj1 = Vec_PtrPop(vSuper);
+ pObj2 = Vec_PtrPop(vSuper);
+ Ivy_NodeBalancePushUniqueOrderByLevel( vSuper, Ivy_Oper(p, pObj1, pObj2, Type) );
+ }
+ return Vec_PtrEntry(vSuper, 0);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the nodes of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeBalanceCone_rec( Ivy_Obj_t * pRoot, Ivy_Obj_t * pObj, Vec_Ptr_t * vSuper )
+{
+ int RetValue1, RetValue2, i;
+ // check if the node is visited
+ if ( Ivy_Regular(pObj)->fMarkB )
+ {
+ // check if the node occurs in the same polarity
+ for ( i = 0; i < vSuper->nSize; i++ )
+ if ( vSuper->pArray[i] == pObj )
+ return 1;
+ // check if the node is present in the opposite polarity
+ for ( i = 0; i < vSuper->nSize; i++ )
+ if ( vSuper->pArray[i] == Ivy_Not(pObj) )
+ return -1;
+ assert( 0 );
+ return 0;
+ }
+ // if the new node is complemented or a PI, another gate begins
+ if ( pObj != pRoot && (Ivy_IsComplement(pObj) || Ivy_ObjType(pObj) != Ivy_ObjType(pRoot) || Ivy_ObjRefs(pObj) > 1) )
+ {
+ Vec_PtrPush( vSuper, pObj );
+ Ivy_Regular(pObj)->fMarkB = 1;
+ return 0;
+ }
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjIsNode(pObj) );
+ // go through the branches
+ RetValue1 = Ivy_NodeBalanceCone_rec( pRoot, Ivy_ObjReal( Ivy_ObjChild0(pObj) ), vSuper );
+ RetValue2 = Ivy_NodeBalanceCone_rec( pRoot, Ivy_ObjReal( Ivy_ObjChild1(pObj) ), vSuper );
+ if ( RetValue1 == -1 || RetValue2 == -1 )
+ return -1;
+ // return 1 if at least one branch has a duplicate
+ return RetValue1 || RetValue2;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the nodes of the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Ivy_NodeBalanceCone( Ivy_Obj_t * pObj, Vec_Vec_t * vStore, int Level )
+{
+ Vec_Ptr_t * vNodes;
+ int RetValue, i;
+ assert( !Ivy_IsComplement(pObj) );
+ // extend the storage
+ if ( Vec_VecSize( vStore ) <= Level )
+ Vec_VecPush( vStore, Level, 0 );
+ // get the temporary array of nodes
+ vNodes = Vec_VecEntry( vStore, Level );
+ Vec_PtrClear( vNodes );
+ // collect the nodes in the implication supergate
+ RetValue = Ivy_NodeBalanceCone_rec( pObj, pObj, vNodes );
+ assert( vNodes->nSize > 1 );
+ // unmark the visited nodes
+ Vec_PtrForEachEntry( vNodes, pObj, i )
+ Ivy_Regular(pObj)->fMarkB = 0;
+ // if we found the node and its complement in the same implication supergate,
+ // return empty set of nodes (meaning that we should use constant-0 node)
+ if ( RetValue == -1 )
+ vNodes->nSize = 0;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds the left bound on the next candidate to be paired.]
+
+ Description [The nodes in the array are in the decreasing order of levels.
+ The last node in the array has the smallest level. By default it would be paired
+ with the next node on the left. However, it may be possible to pair it with some
+ other node on the left, in such a way that the new node is shared. This procedure
+ finds the index of the left-most node, which can be paired with the last node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeBalanceFindLeft( Vec_Ptr_t * vSuper )
+{
+ Ivy_Obj_t * pObjRight, * pObjLeft;
+ int Current;
+ // if two or less nodes, pair with the first
+ if ( Vec_PtrSize(vSuper) < 3 )
+ return 0;
+ // set the pointer to the one before the last
+ Current = Vec_PtrSize(vSuper) - 2;
+ pObjRight = Vec_PtrEntry( vSuper, Current );
+ // go through the nodes to the left of this one
+ for ( Current--; Current >= 0; Current-- )
+ {
+ // get the next node on the left
+ pObjLeft = Vec_PtrEntry( vSuper, Current );
+ // if the level of this node is different, quit the loop
+ if ( Ivy_Regular(pObjLeft)->Level != Ivy_Regular(pObjRight)->Level )
+ break;
+ }
+ Current++;
+ // get the node, for which the equality holds
+ pObjLeft = Vec_PtrEntry( vSuper, Current );
+ assert( Ivy_Regular(pObjLeft)->Level == Ivy_Regular(pObjRight)->Level );
+ return Current;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Moves closer to the end the node that is best for sharing.]
+
+ Description [If there is no node with sharing, randomly chooses one of
+ the legal nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeBalancePermute( Ivy_Man_t * p, Vec_Ptr_t * vSuper, int LeftBound, int fExor )
+{
+ Ivy_Obj_t * pObj1, * pObj2, * pObj3, * pGhost;
+ int RightBound, i;
+ // get the right bound
+ RightBound = Vec_PtrSize(vSuper) - 2;
+ assert( LeftBound <= RightBound );
+ if ( LeftBound == RightBound )
+ return;
+ // get the two last nodes
+ pObj1 = Vec_PtrEntry( vSuper, RightBound + 1 );
+ pObj2 = Vec_PtrEntry( vSuper, RightBound );
+ if ( Ivy_Regular(pObj1) == p->pConst1 || Ivy_Regular(pObj2) == p->pConst1 )
+ return;
+ // find the first node that can be shared
+ for ( i = RightBound; i >= LeftBound; i-- )
+ {
+ pObj3 = Vec_PtrEntry( vSuper, i );
+ if ( Ivy_Regular(pObj3) == p->pConst1 )
+ {
+ Vec_PtrWriteEntry( vSuper, i, pObj2 );
+ Vec_PtrWriteEntry( vSuper, RightBound, pObj3 );
+ return;
+ }
+ pGhost = Ivy_ObjCreateGhost( p, pObj1, pObj3, fExor? IVY_EXOR : IVY_AND, IVY_INIT_NONE );
+ if ( Ivy_TableLookup( p, pGhost ) )
+ {
+ if ( pObj3 == pObj2 )
+ return;
+ Vec_PtrWriteEntry( vSuper, i, pObj2 );
+ Vec_PtrWriteEntry( vSuper, RightBound, pObj3 );
+ return;
+ }
+ }
+/*
+ // we did not find the node to share, randomize choice
+ {
+ int Choice = rand() % (RightBound - LeftBound + 1);
+ pObj3 = Vec_PtrEntry( vSuper, LeftBound + Choice );
+ if ( pObj3 == pObj2 )
+ return;
+ Vec_PtrWriteEntry( vSuper, LeftBound + Choice, pObj2 );
+ Vec_PtrWriteEntry( vSuper, RightBound, pObj3 );
+ }
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeBalancePushUniqueOrderByLevel( Vec_Ptr_t * vStore, Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pObj1, * pObj2;
+ int i;
+ if ( Vec_PtrPushUnique(vStore, pObj) )
+ return;
+ // find the p of the node
+ for ( i = vStore->nSize-1; i > 0; i-- )
+ {
+ pObj1 = vStore->pArray[i ];
+ pObj2 = vStore->pArray[i-1];
+ if ( Ivy_Regular(pObj1)->Level <= Ivy_Regular(pObj2)->Level )
+ break;
+ vStore->pArray[i ] = pObj2;
+ vStore->pArray[i-1] = pObj1;
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyCanon.c b/src/aig/ivy/ivyCanon.c
new file mode 100644
index 00000000..5768b87e
--- /dev/null
+++ b/src/aig/ivy/ivyCanon.c
@@ -0,0 +1,144 @@
+/**CFile****************************************************************
+
+ FileName [ivyCanon.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Finding canonical form of objects.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyCanon.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static Ivy_Obj_t * Ivy_TableLookupPair_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj0, Ivy_Obj_t * pObj1, int fCompl0, int fCompl1, Ivy_Type_t Type );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Creates the canonical form of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_CanonPair_rec( Ivy_Man_t * p, Ivy_Obj_t * pGhost )
+{
+ Ivy_Obj_t * pResult, * pLat0, * pLat1;
+ Ivy_Init_t Init, Init0, Init1;
+ int fCompl0, fCompl1;
+ Ivy_Type_t Type;
+ assert( Ivy_ObjIsNode(pGhost) );
+ assert( Ivy_ObjIsAnd(pGhost) || (!Ivy_ObjFaninC0(pGhost) && !Ivy_ObjFaninC1(pGhost)) );
+ assert( Ivy_ObjFaninId0(pGhost) != 0 && Ivy_ObjFaninId1(pGhost) != 0 );
+ // consider the case when the pair is canonical
+ if ( !Ivy_ObjIsLatch(Ivy_ObjFanin0(pGhost)) || !Ivy_ObjIsLatch(Ivy_ObjFanin1(pGhost)) )
+ {
+ if ( pResult = Ivy_TableLookup( p, pGhost ) )
+ return pResult;
+ return Ivy_ObjCreate( p, pGhost );
+ }
+ /// remember the latches
+ pLat0 = Ivy_ObjFanin0(pGhost);
+ pLat1 = Ivy_ObjFanin1(pGhost);
+ // remember type and compls
+ Type = Ivy_ObjType(pGhost);
+ fCompl0 = Ivy_ObjFaninC0(pGhost);
+ fCompl1 = Ivy_ObjFaninC1(pGhost);
+ // call recursively
+ pResult = Ivy_Oper( p, Ivy_NotCond(Ivy_ObjFanin0(pLat0), fCompl0), Ivy_NotCond(Ivy_ObjFanin0(pLat1), fCompl1), Type );
+ // build latch on top of this
+ Init0 = Ivy_InitNotCond( Ivy_ObjInit(pLat0), fCompl0 );
+ Init1 = Ivy_InitNotCond( Ivy_ObjInit(pLat1), fCompl1 );
+ Init = (Type == IVY_AND)? Ivy_InitAnd(Init0, Init1) : Ivy_InitExor(Init0, Init1);
+ return Ivy_Latch( p, pResult, Init );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the canonical form of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_CanonAnd( Ivy_Man_t * p, Ivy_Obj_t * pObj0, Ivy_Obj_t * pObj1 )
+{
+ Ivy_Obj_t * pGhost, * pResult;
+ pGhost = Ivy_ObjCreateGhost( p, pObj0, pObj1, IVY_AND, IVY_INIT_NONE );
+ pResult = Ivy_CanonPair_rec( p, pGhost );
+ return pResult;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the canonical form of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_CanonExor( Ivy_Man_t * p, Ivy_Obj_t * pObj0, Ivy_Obj_t * pObj1 )
+{
+ Ivy_Obj_t * pGhost, * pResult;
+ int fCompl = Ivy_IsComplement(pObj0) ^ Ivy_IsComplement(pObj1);
+ pObj0 = Ivy_Regular(pObj0);
+ pObj1 = Ivy_Regular(pObj1);
+ pGhost = Ivy_ObjCreateGhost( p, pObj0, pObj1, IVY_EXOR, IVY_INIT_NONE );
+ pResult = Ivy_CanonPair_rec( p, pGhost );
+ return Ivy_NotCond( pResult, fCompl );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the canonical form of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_CanonLatch( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Init_t Init )
+{
+ Ivy_Obj_t * pGhost, * pResult;
+ int fCompl = Ivy_IsComplement(pObj);
+ pObj = Ivy_Regular(pObj);
+ pGhost = Ivy_ObjCreateGhost( p, pObj, NULL, IVY_LATCH, Ivy_InitNotCond(Init, fCompl) );
+ pResult = Ivy_TableLookup( p, pGhost );
+ if ( pResult == NULL )
+ pResult = Ivy_ObjCreate( p, pGhost );
+ return Ivy_NotCond( pResult, fCompl );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyCheck.c b/src/aig/ivy/ivyCheck.c
new file mode 100644
index 00000000..55448f19
--- /dev/null
+++ b/src/aig/ivy/ivyCheck.c
@@ -0,0 +1,273 @@
+/**CFile****************************************************************
+
+ FileName [ivyCheck.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [AIG checking procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyCheck.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Checks the consistency of the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManCheck( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj, * pObj2;
+ int i;
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ // skip deleted nodes
+ if ( Ivy_ObjId(pObj) != i )
+ {
+ printf( "Ivy_ManCheck: Node with ID %d is listed as number %d in the array of objects.\n", pObj->Id, i );
+ return 0;
+ }
+ // consider the constant node and PIs
+ if ( i == 0 || Ivy_ObjIsPi(pObj) )
+ {
+ if ( Ivy_ObjFaninId0(pObj) || Ivy_ObjFaninId1(pObj) || Ivy_ObjLevel(pObj) )
+ {
+ printf( "Ivy_ManCheck: The AIG has non-standard constant or PI node with ID \"%d\".\n", pObj->Id );
+ return 0;
+ }
+ continue;
+ }
+ if ( Ivy_ObjIsPo(pObj) )
+ {
+ if ( Ivy_ObjFaninId1(pObj) )
+ {
+ printf( "Ivy_ManCheck: The AIG has non-standard PO node with ID \"%d\".\n", pObj->Id );
+ return 0;
+ }
+ continue;
+ }
+ if ( Ivy_ObjIsBuf(pObj) )
+ {
+ if ( Ivy_ObjFanin1(pObj) )
+ {
+ printf( "Ivy_ManCheck: The buffer with ID \"%d\" contains second fanin.\n", pObj->Id );
+ return 0;
+ }
+ continue;
+ }
+ if ( Ivy_ObjIsLatch(pObj) )
+ {
+ if ( Ivy_ObjFanin1(pObj) )
+ {
+ printf( "Ivy_ManCheck: The latch with ID \"%d\" contains second fanin.\n", pObj->Id );
+ return 0;
+ }
+ if ( Ivy_ObjInit(pObj) == IVY_INIT_NONE )
+ {
+ printf( "Ivy_ManCheck: The latch with ID \"%d\" does not have initial state.\n", pObj->Id );
+ return 0;
+ }
+ pObj2 = Ivy_TableLookup( p, pObj );
+ if ( pObj2 != pObj )
+ printf( "Ivy_ManCheck: Latch with ID \"%d\" is not in the structural hashing table.\n", pObj->Id );
+ continue;
+ }
+ // consider the AND node
+ if ( !Ivy_ObjFanin0(pObj) || !Ivy_ObjFanin1(pObj) )
+ {
+ printf( "Ivy_ManCheck: The AIG has internal node \"%d\" with a NULL fanin.\n", pObj->Id );
+ return 0;
+ }
+ if ( Ivy_ObjFaninId0(pObj) >= Ivy_ObjFaninId1(pObj) )
+ {
+ printf( "Ivy_ManCheck: The AIG has node \"%d\" with a wrong ordering of fanins.\n", pObj->Id );
+ return 0;
+ }
+ if ( Ivy_ObjLevel(pObj) != Ivy_ObjLevelNew(pObj) )
+ printf( "Ivy_ManCheck: Node with ID \"%d\" has level %d but should have level %d.\n", pObj->Id, Ivy_ObjLevel(pObj), Ivy_ObjLevelNew(pObj) );
+ pObj2 = Ivy_TableLookup( p, pObj );
+ if ( pObj2 != pObj )
+ printf( "Ivy_ManCheck: Node with ID \"%d\" is not in the structural hashing table.\n", pObj->Id );
+ if ( Ivy_ObjRefs(pObj) == 0 )
+ printf( "Ivy_ManCheck: Node with ID \"%d\" has no fanouts.\n", pObj->Id );
+ // check fanouts
+ 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
+ if ( Ivy_TableCountEntries(p) != Ivy_ManAndNum(p) + Ivy_ManExorNum(p) + Ivy_ManLatchNum(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;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Verifies the fanouts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManCheckFanoutNums( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i, Counter = 0;
+ Ivy_ManForEachObj( p, pObj, i )
+ if ( Ivy_ObjIsNode(pObj) )
+ Counter += (Ivy_ObjRefs(pObj) == 0);
+ if ( Counter )
+ printf( "Sequential AIG has %d dangling nodes.\n", Counter );
+ return Counter;
+}
+
+/**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;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks that each choice node has exactly one node with fanouts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManCheckChoices( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj, * pTemp;
+ int i;
+ Ivy_ManForEachObj( p->pHaig, pObj, i )
+ {
+ if ( Ivy_ObjRefs(pObj) == 0 )
+ continue;
+ // count the number of nodes in the loop
+ assert( !Ivy_IsComplement(pObj->pEquiv) );
+ for ( pTemp = pObj->pEquiv; pTemp && pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ if ( Ivy_ObjRefs(pTemp) > 1 )
+ printf( "Node %d has member %d in its equiv class with %d fanouts.\n", pObj->Id, pTemp->Id, Ivy_ObjRefs(pTemp) );
+ }
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyCut.c b/src/aig/ivy/ivyCut.c
new file mode 100644
index 00000000..e257d8a6
--- /dev/null
+++ b/src/aig/ivy/ivyCut.c
@@ -0,0 +1,989 @@
+/**CFile****************************************************************
+
+ FileName [ivyCut.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Computes reconvergence driven sequential cut.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyCut.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static inline int Ivy_NodeCutHashValue( int NodeId ) { return 1 << (NodeId % 31); }
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Evaluate the cost of removing the node from the set of leaves.]
+
+ Description [Returns the number of new leaves that will be brought in.
+ Returns large number if the node cannot be removed from the set of leaves.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_NodeGetLeafCostOne( Ivy_Man_t * p, int Leaf, Vec_Int_t * vInside )
+{
+ Ivy_Obj_t * pNode;
+ int nLatches, FaninLeaf, Cost;
+ // make sure leaf is not a contant node
+ assert( Leaf > 0 );
+ // get the node
+ pNode = Ivy_ManObj( p, Ivy_LeafId(Leaf) );
+ // cannot expand over the PI node
+ if ( Ivy_ObjIsPi(pNode) || Ivy_ObjIsConst1(pNode) )
+ return 999;
+ // get the number of latches
+ nLatches = Ivy_LeafLat(Leaf) + Ivy_ObjIsLatch(pNode);
+ if ( nLatches > 15 )
+ return 999;
+ // get the first fanin
+ FaninLeaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pNode), nLatches );
+ Cost = FaninLeaf && (Vec_IntFind(vInside, FaninLeaf) == -1);
+ // quit if this is the one fanin node
+ if ( Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) )
+ return Cost;
+ assert( Ivy_ObjIsNode(pNode) );
+ // get the second fanin
+ FaninLeaf = Ivy_LeafCreate( Ivy_ObjFaninId1(pNode), nLatches );
+ Cost += FaninLeaf && (Vec_IntFind(vInside, FaninLeaf) == -1);
+ return Cost;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Builds reconvergence-driven cut by changing one leaf at a time.]
+
+ Description [This procedure looks at the current leaves and tries to change
+ one leaf at a time in such a way that the cut grows as little as possible.
+ In evaluating the fanins, this procedure looks only at their immediate
+ predecessors (this is why it is called a one-level construction procedure).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManSeqFindCut_int( Ivy_Man_t * p, Vec_Int_t * vFront, Vec_Int_t * vInside, int nSizeLimit )
+{
+ Ivy_Obj_t * pNode;
+ int CostBest, CostCur, Leaf, LeafBest, Next, nLatches, i;
+ int LeavesBest[10];
+ int Counter;
+
+ // add random selection of the best fanin!!!
+
+ // find the best fanin
+ CostBest = 99;
+ LeafBest = -1;
+ Counter = -1;
+//printf( "Evaluating fanins of the cut:\n" );
+ Vec_IntForEachEntry( vFront, Leaf, i )
+ {
+ CostCur = Ivy_NodeGetLeafCostOne( p, Leaf, vInside );
+//printf( " Fanin %s has cost %d.\n", Ivy_ObjName(pNode), CostCur );
+ if ( CostBest > CostCur )
+ {
+ CostBest = CostCur;
+ LeafBest = Leaf;
+ LeavesBest[0] = Leaf;
+ Counter = 1;
+ }
+ else if ( CostBest == CostCur )
+ LeavesBest[Counter++] = Leaf;
+
+ if ( CostBest <= 1 ) // can be if ( CostBest <= 1 )
+ break;
+ }
+ if ( CostBest == 99 )
+ return 0;
+// return Ivy_NodeBuildCutLevelTwo_int( vInside, vFront, nFaninLimit );
+
+ assert( CostBest < 3 );
+ if ( Vec_IntSize(vFront) - 1 + CostBest > nSizeLimit )
+ return 0;
+// return Ivy_NodeBuildCutLevelTwo_int( vInside, vFront, nFaninLimit );
+
+ assert( Counter > 0 );
+printf( "%d", Counter );
+
+ LeafBest = LeavesBest[rand() % Counter];
+
+ // remove the node from the array
+ assert( LeafBest >= 0 );
+ Vec_IntRemove( vFront, LeafBest );
+//printf( "Removing fanin %s.\n", Ivy_ObjName(pNode) );
+
+ // get the node and its latches
+ pNode = Ivy_ManObj( p, Ivy_LeafId(LeafBest) );
+ nLatches = Ivy_LeafLat(LeafBest) + Ivy_ObjIsLatch(pNode);
+ assert( Ivy_ObjIsNode(pNode) || Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) );
+
+ // add the left child to the fanins
+ Next = Ivy_LeafCreate( Ivy_ObjFaninId0(pNode), nLatches );
+ if ( Next && Vec_IntFind(vInside, Next) == -1 )
+ {
+//printf( "Adding fanin %s.\n", Ivy_ObjName(pNext) );
+ Vec_IntPush( vFront, Next );
+ Vec_IntPush( vInside, Next );
+ }
+
+ // quit if this is the one fanin node
+ if ( Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) )
+ return 1;
+ assert( Ivy_ObjIsNode(pNode) );
+
+ // add the right child to the fanins
+ Next = Ivy_LeafCreate( Ivy_ObjFaninId1(pNode), nLatches );
+ if ( Next && Vec_IntFind(vInside, Next) == -1 )
+ {
+//printf( "Adding fanin %s.\n", Ivy_ObjName(pNext) );
+ Vec_IntPush( vFront, Next );
+ Vec_IntPush( vInside, Next );
+ }
+ assert( Vec_IntSize(vFront) <= nSizeLimit );
+ // keep doing this
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes one sequential cut of the given size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManSeqFindCut( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Int_t * vFront, Vec_Int_t * vInside, int nSize )
+{
+ assert( !Ivy_IsComplement(pRoot) );
+ assert( Ivy_ObjIsNode(pRoot) );
+ assert( Ivy_ObjFaninId0(pRoot) );
+ assert( Ivy_ObjFaninId1(pRoot) );
+
+ // start the cut
+ Vec_IntClear( vFront );
+ Vec_IntPush( vFront, Ivy_LeafCreate(Ivy_ObjFaninId0(pRoot), 0) );
+ Vec_IntPush( vFront, Ivy_LeafCreate(Ivy_ObjFaninId1(pRoot), 0) );
+
+ // start the visited nodes
+ Vec_IntClear( vInside );
+ Vec_IntPush( vInside, Ivy_LeafCreate(pRoot->Id, 0) );
+ Vec_IntPush( vInside, Ivy_LeafCreate(Ivy_ObjFaninId0(pRoot), 0) );
+ Vec_IntPush( vInside, Ivy_LeafCreate(Ivy_ObjFaninId1(pRoot), 0) );
+
+ // compute the cut
+ while ( Ivy_ManSeqFindCut_int( p, vFront, vInside, nSize ) );
+ assert( Vec_IntSize(vFront) <= nSize );
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Computing Boolean cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManFindBoolCut_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vVolume, Ivy_Obj_t * pPivot )
+{
+ int RetValue0, RetValue1;
+ if ( pObj == pPivot )
+ {
+ Vec_PtrPushUnique( vLeaves, pObj );
+ Vec_PtrPushUnique( vVolume, pObj );
+ return 1;
+ }
+ if ( pObj->fMarkA )
+ return 0;
+
+// assert( !Ivy_ObjIsCi(pObj) );
+ if ( Ivy_ObjIsCi(pObj) )
+ return 0;
+
+ if ( Ivy_ObjIsBuf(pObj) )
+ {
+ RetValue0 = Ivy_ManFindBoolCut_rec( p, Ivy_ObjFanin0(pObj), vLeaves, vVolume, pPivot );
+ if ( !RetValue0 )
+ return 0;
+ Vec_PtrPushUnique( vVolume, pObj );
+ return 1;
+ }
+ assert( Ivy_ObjIsNode(pObj) );
+ RetValue0 = Ivy_ManFindBoolCut_rec( p, Ivy_ObjFanin0(pObj), vLeaves, vVolume, pPivot );
+ RetValue1 = Ivy_ManFindBoolCut_rec( p, Ivy_ObjFanin1(pObj), vLeaves, vVolume, pPivot );
+ if ( !RetValue0 && !RetValue1 )
+ return 0;
+ // add new leaves
+ if ( !RetValue0 )
+ {
+ Vec_PtrPushUnique( vLeaves, Ivy_ObjFanin0(pObj) );
+ Vec_PtrPushUnique( vVolume, Ivy_ObjFanin0(pObj) );
+ }
+ if ( !RetValue1 )
+ {
+ Vec_PtrPushUnique( vLeaves, Ivy_ObjFanin1(pObj) );
+ Vec_PtrPushUnique( vVolume, Ivy_ObjFanin1(pObj) );
+ }
+ Vec_PtrPushUnique( vVolume, pObj );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the cost of one node (how many new nodes are added.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManFindBoolCutCost( Ivy_Obj_t * pObj )
+{
+ int Cost;
+ // make sure the node is in the construction zone
+ assert( pObj->fMarkA == 1 );
+ // cannot expand over the PI node
+ if ( Ivy_ObjIsCi(pObj) )
+ return 999;
+ // always expand over the buffer
+ if ( Ivy_ObjIsBuf(pObj) )
+ return !Ivy_ObjFanin0(pObj)->fMarkA;
+ // get the cost of the cone
+ Cost = (!Ivy_ObjFanin0(pObj)->fMarkA) + (!Ivy_ObjFanin1(pObj)->fMarkA);
+ // return the number of nodes to be added to the leaves if this node is removed
+ return Cost;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computing Boolean cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManFindBoolCut( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Ptr_t * vFront, Vec_Ptr_t * vVolume, Vec_Ptr_t * vLeaves )
+{
+ Ivy_Obj_t * pObj, * pFaninC, * pFanin0, * pFanin1, * pPivot;
+ int RetValue, LevelLimit, Lev, k;
+ assert( !Ivy_IsComplement(pRoot) );
+ // clear the frontier and collect the nodes
+ Vec_PtrClear( vFront );
+ Vec_PtrClear( vVolume );
+ if ( Ivy_ObjIsMuxType(pRoot) )
+ pFaninC = Ivy_ObjRecognizeMux( pRoot, &pFanin0, &pFanin1 );
+ else
+ {
+ pFaninC = NULL;
+ pFanin0 = Ivy_ObjFanin0(pRoot);
+ pFanin1 = Ivy_ObjFanin1(pRoot);
+ }
+ // start cone A
+ pFanin0->fMarkA = 1;
+ Vec_PtrPush( vFront, pFanin0 );
+ Vec_PtrPush( vVolume, pFanin0 );
+ // start cone B
+ pFanin1->fMarkB = 1;
+ Vec_PtrPush( vFront, pFanin1 );
+ Vec_PtrPush( vVolume, pFanin1 );
+ // iteratively expand until the common node (pPivot) is found or limit is reached
+ assert( Ivy_ObjLevel(pRoot) == Ivy_ObjLevelNew(pRoot) );
+ pPivot = NULL;
+ LevelLimit = IVY_MAX( Ivy_ObjLevel(pRoot) - 10, 1 );
+ for ( Lev = Ivy_ObjLevel(pRoot) - 1; Lev >= LevelLimit; Lev-- )
+ {
+ while ( 1 )
+ {
+ // find the next node to expand on this level
+ Vec_PtrForEachEntry( vFront, pObj, k )
+ if ( (int)pObj->Level == Lev )
+ break;
+ if ( k == Vec_PtrSize(vFront) )
+ break;
+ assert( (int)pObj->Level <= Lev );
+ assert( pObj->fMarkA ^ pObj->fMarkB );
+ // remove the old node
+ Vec_PtrRemove( vFront, pObj );
+
+ // expand this node
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ if ( !pFanin0->fMarkA && !pFanin0->fMarkB )
+ {
+ Vec_PtrPush( vFront, pFanin0 );
+ Vec_PtrPush( vVolume, pFanin0 );
+ }
+ // mark the new nodes
+ if ( pObj->fMarkA )
+ pFanin0->fMarkA = 1;
+ if ( pObj->fMarkB )
+ pFanin0->fMarkB = 1;
+
+ if ( Ivy_ObjIsBuf(pObj) )
+ {
+ if ( pFanin0->fMarkA && pFanin0->fMarkB )
+ {
+ pPivot = pFanin0;
+ break;
+ }
+ continue;
+ }
+
+ // expand this node
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ if ( !pFanin1->fMarkA && !pFanin1->fMarkB )
+ {
+ Vec_PtrPush( vFront, pFanin1 );
+ Vec_PtrPush( vVolume, pFanin1 );
+ }
+ // mark the new nodes
+ if ( pObj->fMarkA )
+ pFanin1->fMarkA = 1;
+ if ( pObj->fMarkB )
+ pFanin1->fMarkB = 1;
+
+ // consider if it is time to quit
+ if ( pFanin0->fMarkA && pFanin0->fMarkB )
+ {
+ pPivot = pFanin0;
+ break;
+ }
+ if ( pFanin1->fMarkA && pFanin1->fMarkB )
+ {
+ pPivot = pFanin1;
+ break;
+ }
+ }
+ if ( pPivot != NULL )
+ break;
+ }
+ if ( pPivot == NULL )
+ return 0;
+ // if the MUX control is defined, it should not be
+ if ( pFaninC && !pFaninC->fMarkA && !pFaninC->fMarkB )
+ Vec_PtrPush( vFront, pFaninC );
+ // clean the markings
+ Vec_PtrForEachEntry( vVolume, pObj, k )
+ pObj->fMarkA = pObj->fMarkB = 0;
+
+ // mark the nodes on the frontier (including the pivot)
+ Vec_PtrForEachEntry( vFront, pObj, k )
+ pObj->fMarkA = 1;
+ // cut exists, collect all the nodes on the shortest path to the pivot
+ Vec_PtrClear( vLeaves );
+ Vec_PtrClear( vVolume );
+ RetValue = Ivy_ManFindBoolCut_rec( p, pRoot, vLeaves, vVolume, pPivot );
+ assert( RetValue == 1 );
+ // unmark the nodes on the frontier (including the pivot)
+ Vec_PtrForEachEntry( vFront, pObj, k )
+ pObj->fMarkA = 0;
+
+ // mark the nodes in the volume
+ Vec_PtrForEachEntry( vVolume, pObj, k )
+ pObj->fMarkA = 1;
+ // expand the cut without increasing its size
+ while ( 1 )
+ {
+ Vec_PtrForEachEntry( vLeaves, pObj, k )
+ if ( Ivy_ManFindBoolCutCost(pObj) < 2 )
+ break;
+ if ( k == Vec_PtrSize(vLeaves) )
+ break;
+ // the node can be expanded
+ // remove the old node
+ Vec_PtrRemove( vLeaves, pObj );
+ // expand this node
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ if ( !pFanin0->fMarkA )
+ {
+ pFanin0->fMarkA = 1;
+ Vec_PtrPush( vVolume, pFanin0 );
+ Vec_PtrPush( vLeaves, pFanin0 );
+ }
+ if ( Ivy_ObjIsBuf(pObj) )
+ continue;
+ // expand this node
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ if ( !pFanin1->fMarkA )
+ {
+ pFanin1->fMarkA = 1;
+ Vec_PtrPush( vVolume, pFanin1 );
+ Vec_PtrPush( vLeaves, pFanin1 );
+ }
+ }
+ // unmark the nodes in the volume
+ Vec_PtrForEachEntry( vVolume, pObj, k )
+ pObj->fMarkA = 0;
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManTestCutsBool( Ivy_Man_t * p )
+{
+ Vec_Ptr_t * vFront, * vVolume, * vLeaves;
+ Ivy_Obj_t * pObj;//, * pTemp;
+ int i, RetValue;//, k;
+ vFront = Vec_PtrAlloc( 100 );
+ vVolume = Vec_PtrAlloc( 100 );
+ vLeaves = Vec_PtrAlloc( 100 );
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ if ( !Ivy_ObjIsNode(pObj) )
+ continue;
+ if ( Ivy_ObjIsMuxType(pObj) )
+ {
+ printf( "m" );
+ continue;
+ }
+ if ( Ivy_ObjIsExor(pObj) )
+ printf( "x" );
+ RetValue = Ivy_ManFindBoolCut( p, pObj, vFront, vVolume, vLeaves );
+ if ( RetValue == 0 )
+ printf( "- " );
+ else
+ printf( "%d ", Vec_PtrSize(vLeaves) );
+/*
+ printf( "( " );
+ Vec_PtrForEachEntry( vFront, pTemp, k )
+ printf( "%d ", Ivy_ObjRefs(Ivy_Regular(pTemp)) );
+ printf( ")\n" );
+*/
+ }
+ printf( "\n" );
+ Vec_PtrFree( vFront );
+ Vec_PtrFree( vVolume );
+ Vec_PtrFree( vLeaves );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Find the hash value of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline unsigned Ivy_NodeCutHash( Ivy_Cut_t * pCut )
+{
+ int i;
+// for ( i = 1; i < pCut->nSize; i++ )
+// assert( pCut->pArray[i-1] < pCut->pArray[i] );
+ pCut->uHash = 0;
+ for ( i = 0; i < pCut->nSize; i++ )
+ pCut->uHash |= (1 << (pCut->pArray[i] % 31));
+ return pCut->uHash;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes one node to the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Ivy_NodeCutShrink( Ivy_Cut_t * pCut, int iOld )
+{
+ int i, k;
+ for ( i = k = 0; i < pCut->nSize; i++ )
+ if ( pCut->pArray[i] != iOld )
+ pCut->pArray[k++] = pCut->pArray[i];
+ assert( k == pCut->nSize - 1 );
+ pCut->nSize--;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one node to the cut.]
+
+ Description [Returns 1 if the cuts is still okay.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_NodeCutExtend( Ivy_Cut_t * pCut, int iNew )
+{
+ int i;
+ for ( i = 0; i < pCut->nSize; i++ )
+ if ( pCut->pArray[i] == iNew )
+ return 1;
+ // check if there is room
+ if ( pCut->nSize == pCut->nSizeMax )
+ return 0;
+ // add the new one
+ for ( i = pCut->nSize - 1; i >= 0; i-- )
+ if ( pCut->pArray[i] > iNew )
+ pCut->pArray[i+1] = pCut->pArray[i];
+ else
+ {
+ assert( pCut->pArray[i] < iNew );
+ break;
+ }
+ pCut->pArray[i+1] = iNew;
+ pCut->nSize++;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the cut can be constructed; 0 otherwise.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_NodeCutPrescreen( Ivy_Cut_t * pCut, int Id0, int Id1 )
+{
+ int i;
+ if ( pCut->nSize < pCut->nSizeMax )
+ return 1;
+ for ( i = 0; i < pCut->nSize; i++ )
+ if ( pCut->pArray[i] == Id0 || pCut->pArray[i] == Id1 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives new cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_NodeCutDeriveNew( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
+{
+ unsigned uHash = 0;
+ int i, k;
+ assert( pCut->nSize > 0 );
+ assert( IdNew0 < IdNew1 );
+ for ( i = k = 0; i < pCut->nSize; i++ )
+ {
+ if ( pCut->pArray[i] == IdOld )
+ continue;
+ if ( IdNew0 <= pCut->pArray[i] )
+ {
+ if ( IdNew0 < pCut->pArray[i] )
+ {
+ pCutNew->pArray[ k++ ] = IdNew0;
+ uHash |= Ivy_NodeCutHashValue( IdNew0 );
+ }
+ IdNew0 = 0x7FFFFFFF;
+ }
+ if ( IdNew1 <= pCut->pArray[i] )
+ {
+ if ( IdNew1 < pCut->pArray[i] )
+ {
+ pCutNew->pArray[ k++ ] = IdNew1;
+ uHash |= Ivy_NodeCutHashValue( IdNew1 );
+ }
+ IdNew1 = 0x7FFFFFFF;
+ }
+ pCutNew->pArray[ k++ ] = pCut->pArray[i];
+ uHash |= Ivy_NodeCutHashValue( pCut->pArray[i] );
+ }
+ if ( IdNew0 < 0x7FFFFFFF )
+ {
+ pCutNew->pArray[ k++ ] = IdNew0;
+ uHash |= Ivy_NodeCutHashValue( IdNew0 );
+ }
+ if ( IdNew1 < 0x7FFFFFFF )
+ {
+ pCutNew->pArray[ k++ ] = IdNew1;
+ uHash |= Ivy_NodeCutHashValue( IdNew1 );
+ }
+ pCutNew->nSize = k;
+ pCutNew->uHash = uHash;
+ assert( pCutNew->nSize <= pCut->nSizeMax );
+// for ( i = 1; i < pCutNew->nSize; i++ )
+// assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Check if the cut exists.]
+
+ Description [Returns 1 if the cut exists.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeCutFindOrAdd( Ivy_Store_t * pCutStore, Ivy_Cut_t * pCutNew )
+{
+ Ivy_Cut_t * pCut;
+ int i, k;
+ assert( pCutNew->uHash );
+ // try to find the cut
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ {
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->uHash == pCutNew->uHash && pCut->nSize == pCutNew->nSize )
+ {
+ for ( k = 0; k < pCutNew->nSize; k++ )
+ if ( pCut->pArray[k] != pCutNew->pArray[k] )
+ break;
+ if ( k == pCutNew->nSize )
+ return 1;
+ }
+ }
+ assert( pCutStore->nCuts < pCutStore->nCutsMax );
+ // add the cut
+ pCut = pCutStore->pCuts + pCutStore->nCuts++;
+ *pCut = *pCutNew;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if pDom is contained in pCut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutCheckDominance( Ivy_Cut_t * pDom, Ivy_Cut_t * pCut )
+{
+ int i, k;
+ for ( i = 0; i < pDom->nSize; i++ )
+ {
+ for ( k = 0; k < pCut->nSize; k++ )
+ if ( pDom->pArray[i] == pCut->pArray[k] )
+ break;
+ if ( k == pCut->nSize ) // node i in pDom is not contained in pCut
+ return 0;
+ }
+ // every node in pDom is contained in pCut
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Check if the cut exists.]
+
+ Description [Returns 1 if the cut exists.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeCutFindOrAddFilter( Ivy_Store_t * pCutStore, Ivy_Cut_t * pCutNew )
+{
+ Ivy_Cut_t * pCut;
+ int i, k;
+ assert( pCutNew->uHash );
+ // try to find the cut
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ {
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->nSize == 0 )
+ continue;
+ if ( pCut->nSize == pCutNew->nSize )
+ {
+ if ( pCut->uHash == pCutNew->uHash )
+ {
+ for ( k = 0; k < pCutNew->nSize; k++ )
+ if ( pCut->pArray[k] != pCutNew->pArray[k] )
+ break;
+ if ( k == pCutNew->nSize )
+ return 1;
+ }
+ continue;
+ }
+ if ( pCut->nSize < pCutNew->nSize )
+ {
+ // skip the non-contained cuts
+ if ( (pCut->uHash & pCutNew->uHash) != pCut->uHash )
+ continue;
+ // check containment seriously
+ if ( Ivy_CutCheckDominance( pCut, pCutNew ) )
+ return 1;
+ continue;
+ }
+ // check potential containment of other cut
+
+ // skip the non-contained cuts
+ if ( (pCut->uHash & pCutNew->uHash) != pCutNew->uHash )
+ continue;
+ // check containment seriously
+ if ( Ivy_CutCheckDominance( pCutNew, pCut ) )
+ {
+ // remove the current cut
+// --pCutStore->nCuts;
+// for ( k = i; k < pCutStore->nCuts; k++ )
+// pCutStore->pCuts[k] = pCutStore->pCuts[k+1];
+// i--;
+ pCut->nSize = 0;
+ }
+ }
+ assert( pCutStore->nCuts < pCutStore->nCutsMax );
+ // add the cut
+ pCut = pCutStore->pCuts + pCutStore->nCuts++;
+ *pCut = *pCutNew;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Print the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeCompactCuts( Ivy_Store_t * pCutStore )
+{
+ Ivy_Cut_t * pCut;
+ int i, k;
+ for ( i = k = 0; i < pCutStore->nCuts; i++ )
+ {
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->nSize == 0 )
+ continue;
+ pCutStore->pCuts[k++] = *pCut;
+ }
+ pCutStore->nCuts = k;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Print the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodePrintCut( Ivy_Cut_t * pCut )
+{
+ int i;
+ assert( pCut->nSize > 0 );
+ printf( "%d : {", pCut->nSize );
+ for ( i = 0; i < pCut->nSize; i++ )
+ printf( " %d", pCut->pArray[i] );
+ printf( " }\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodePrintCuts( Ivy_Store_t * pCutStore )
+{
+ int i;
+ printf( "Node %d\n", pCutStore->pCuts[0].pArray[0] );
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ 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 []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Store_t * Ivy_NodeFindCutsAll( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves )
+{
+ static Ivy_Store_t CutStore, * pCutStore = &CutStore;
+ Ivy_Cut_t CutNew, * pCutNew = &CutNew, * pCut;
+ Ivy_Obj_t * pLeaf;
+ int i, k, iLeaf0, iLeaf1;
+
+ assert( nLeaves <= IVY_CUT_INPUT );
+
+ // start the structure
+ pCutStore->nCuts = 0;
+ pCutStore->nCutsMax = IVY_CUT_LIMIT;
+ // start the trivial cut
+ pCutNew->uHash = 0;
+ pCutNew->nSize = 1;
+ pCutNew->nSizeMax = nLeaves;
+ pCutNew->pArray[0] = pObj->Id;
+ Ivy_NodeCutHash( pCutNew );
+ // add the trivial cut
+ Ivy_NodeCutFindOrAdd( pCutStore, pCutNew );
+ assert( pCutStore->nCuts == 1 );
+
+ // explore the cuts
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ {
+ // expand this cut
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->nSize == 0 )
+ continue;
+ for ( k = 0; k < pCut->nSize; k++ )
+ {
+ pLeaf = Ivy_ManObj( p, pCut->pArray[k] );
+ if ( Ivy_ObjIsCi(pLeaf) )
+ continue;
+/*
+ *pCutNew = *pCut;
+ Ivy_NodeCutShrink( pCutNew, pLeaf->Id );
+ if ( !Ivy_NodeCutExtend( pCutNew, Ivy_ObjFaninId0(pLeaf) ) )
+ continue;
+ if ( Ivy_ObjIsNode(pLeaf) && !Ivy_NodeCutExtend( pCutNew, Ivy_ObjFaninId1(pLeaf) ) )
+ continue;
+ Ivy_NodeCutHash( pCutNew );
+*/
+ iLeaf0 = Ivy_ObjId( Ivy_ObjRealFanin(Ivy_ObjFanin0(pLeaf)) );
+ iLeaf1 = Ivy_ObjId( Ivy_ObjRealFanin(Ivy_ObjFanin1(pLeaf)) );
+// if ( iLeaf0 == iLeaf1 ) // strange situation observed on Jan 18, 2007
+// continue;
+ if ( !Ivy_NodeCutPrescreen( pCut, iLeaf0, iLeaf1 ) )
+ continue;
+ 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;
+ }
+ if ( pCutStore->nCuts == IVY_CUT_LIMIT )
+ break;
+ }
+ Ivy_NodeCompactCuts( pCutStore );
+// Ivy_NodePrintCuts( pCutStore );
+ return pCutStore;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManTestCutsAll( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i, nCutsCut, nCutsTotal, nNodeTotal, nNodeOver;
+ int clk = clock();
+ nNodeTotal = nNodeOver = 0;
+ nCutsTotal = -Ivy_ManNodeNum(p);
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ if ( !Ivy_ObjIsNode(pObj) )
+ continue;
+ nCutsCut = Ivy_NodeFindCutsAll( p, pObj, 5 )->nCuts;
+ nCutsTotal += nCutsCut;
+ nNodeOver += (nCutsCut == IVY_CUT_LIMIT);
+ nNodeTotal++;
+ }
+ printf( "Total cuts = %6d. Trivial = %6d. Nodes = %6d. Satur = %6d. ",
+ nCutsTotal, Ivy_ManPiNum(p) + Ivy_ManNodeNum(p), nNodeTotal, nNodeOver );
+ PRT( "Time", clock() - clk );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyCutTrav.c b/src/aig/ivy/ivyCutTrav.c
new file mode 100644
index 00000000..ea57c9f5
--- /dev/null
+++ b/src/aig/ivy/ivyCutTrav.c
@@ -0,0 +1,473 @@
+/**CFile****************************************************************
+
+ FileName [ivyCutTrav.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis []
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyCutTrav.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static unsigned * Ivy_NodeCutElementary( Vec_Int_t * vStore, int nWords, int NodeId );
+static void Ivy_NodeComputeVolume( Ivy_Obj_t * pObj, int nNodeLimit, Vec_Ptr_t * vNodes, Vec_Ptr_t * vFront );
+static void Ivy_NodeFindCutsMerge( Vec_Ptr_t * vCuts0, Vec_Ptr_t * vCuts1, Vec_Ptr_t * vCuts, int nLeaves, int nWords, Vec_Int_t * vStore );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes cuts for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Store_t * Ivy_NodeFindCutsTravAll( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves, int nNodeLimit,
+ Vec_Ptr_t * vNodes, Vec_Ptr_t * vFront, Vec_Int_t * vStore, Vec_Vec_t * vBitCuts )
+{
+ static Ivy_Store_t CutStore, * pCutStore = &CutStore;
+ Vec_Ptr_t * vCuts, * vCuts0, * vCuts1;
+ unsigned * pBitCut;
+ Ivy_Obj_t * pLeaf;
+ Ivy_Cut_t * pCut;
+ int i, k, nWords, nNodes;
+
+ assert( nLeaves <= IVY_CUT_INPUT );
+
+ // find the given number of nodes in the TFI
+ Ivy_NodeComputeVolume( pObj, nNodeLimit - 1, vNodes, vFront );
+ nNodes = Vec_PtrSize(vNodes);
+// assert( nNodes <= nNodeLimit );
+
+ // make sure vBitCuts has enough room
+ Vec_VecExpand( vBitCuts, nNodes-1 );
+ Vec_VecClear( vBitCuts );
+
+ // prepare the memory manager
+ Vec_IntClear( vStore );
+ Vec_IntGrow( vStore, 64000 );
+
+ // set elementary cuts for the leaves
+ nWords = Extra_BitWordNum( nNodes );
+ Vec_PtrForEachEntry( vFront, pLeaf, i )
+ {
+ assert( Ivy_ObjTravId(pLeaf) < nNodes );
+ // get the new bitcut
+ pBitCut = Ivy_NodeCutElementary( vStore, nWords, Ivy_ObjTravId(pLeaf) );
+ // set it as the cut of this leaf
+ Vec_VecPush( vBitCuts, Ivy_ObjTravId(pLeaf), pBitCut );
+ }
+
+ // compute the cuts for each node
+ Vec_PtrForEachEntry( vNodes, pLeaf, i )
+ {
+ // skip the leaves
+ vCuts = Vec_VecEntry( vBitCuts, Ivy_ObjTravId(pLeaf) );
+ if ( Vec_PtrSize(vCuts) > 0 )
+ continue;
+ // add elementary cut
+ pBitCut = Ivy_NodeCutElementary( vStore, nWords, Ivy_ObjTravId(pLeaf) );
+ // set it as the cut of this leaf
+ Vec_VecPush( vBitCuts, Ivy_ObjTravId(pLeaf), pBitCut );
+ // get the fanin cuts
+ vCuts0 = Vec_VecEntry( vBitCuts, Ivy_ObjTravId( Ivy_ObjFanin0(pLeaf) ) );
+ vCuts1 = Vec_VecEntry( vBitCuts, Ivy_ObjTravId( Ivy_ObjFanin1(pLeaf) ) );
+ assert( Vec_PtrSize(vCuts0) > 0 );
+ assert( Vec_PtrSize(vCuts1) > 0 );
+ // merge the cuts
+ Ivy_NodeFindCutsMerge( vCuts0, vCuts1, vCuts, nLeaves, nWords, vStore );
+ }
+
+ // start the structure
+ pCutStore->nCuts = 0;
+ pCutStore->nCutsMax = IVY_CUT_LIMIT;
+ // collect the cuts of the root node
+ vCuts = Vec_VecEntry( vBitCuts, Ivy_ObjTravId(pObj) );
+ Vec_PtrForEachEntry( vCuts, pBitCut, i )
+ {
+ pCut = pCutStore->pCuts + pCutStore->nCuts++;
+ pCut->nSize = 0;
+ pCut->nSizeMax = nLeaves;
+ pCut->uHash = 0;
+ for ( k = 0; k < nNodes; k++ )
+ if ( Extra_TruthHasBit(pBitCut, k) )
+ pCut->pArray[ pCut->nSize++ ] = Ivy_ObjId( Vec_PtrEntry(vNodes, k) );
+ assert( pCut->nSize <= nLeaves );
+ if ( pCutStore->nCuts == pCutStore->nCutsMax )
+ break;
+ }
+
+ // clean the travIds
+ Vec_PtrForEachEntry( vNodes, pLeaf, i )
+ pLeaf->TravId = 0;
+ return pCutStore;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates elementary bit-cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned * Ivy_NodeCutElementary( Vec_Int_t * vStore, int nWords, int NodeId )
+{
+ unsigned * pBitCut;
+ pBitCut = Vec_IntFetch( vStore, nWords );
+ memset( pBitCut, 0, 4 * nWords );
+ Extra_TruthSetBit( pBitCut, NodeId );
+ return pBitCut;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compares the node by level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_CompareNodesByLevel( Ivy_Obj_t ** ppObj1, Ivy_Obj_t ** ppObj2 )
+{
+ Ivy_Obj_t * pObj1 = *ppObj1;
+ Ivy_Obj_t * pObj2 = *ppObj2;
+ if ( pObj1->Level < pObj2->Level )
+ return -1;
+ if ( pObj1->Level > pObj2->Level )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Mark all nodes up to the given depth.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeComputeVolumeTrav1_rec( Ivy_Obj_t * pObj, int Depth )
+{
+ if ( Ivy_ObjIsCi(pObj) || Depth == 0 )
+ return;
+ Ivy_NodeComputeVolumeTrav1_rec( Ivy_ObjFanin0(pObj), Depth - 1 );
+ Ivy_NodeComputeVolumeTrav1_rec( Ivy_ObjFanin1(pObj), Depth - 1 );
+ pObj->fMarkA = 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect the marked nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeComputeVolumeTrav2_rec( Ivy_Obj_t * pObj, Vec_Ptr_t * vNodes )
+{
+ if ( !pObj->fMarkA )
+ return;
+ Ivy_NodeComputeVolumeTrav2_rec( Ivy_ObjFanin0(pObj), vNodes );
+ Ivy_NodeComputeVolumeTrav2_rec( Ivy_ObjFanin1(pObj), vNodes );
+ Vec_PtrPush( vNodes, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeComputeVolume( Ivy_Obj_t * pObj, int nNodeLimit, Vec_Ptr_t * vNodes, Vec_Ptr_t * vFront )
+{
+ Ivy_Obj_t * pTemp, * pFanin;
+ int i, nNodes;
+ // mark nodes up to the given depth
+ Ivy_NodeComputeVolumeTrav1_rec( pObj, 6 );
+ // collect the marked nodes
+ Vec_PtrClear( vFront );
+ Ivy_NodeComputeVolumeTrav2_rec( pObj, vFront );
+ // find the fanins that are not marked
+ Vec_PtrClear( vNodes );
+ Vec_PtrForEachEntry( vFront, pTemp, i )
+ {
+ pFanin = Ivy_ObjFanin0(pTemp);
+ if ( !pFanin->fMarkA )
+ {
+ pFanin->fMarkA = 1;
+ Vec_PtrPush( vNodes, pFanin );
+ }
+ pFanin = Ivy_ObjFanin1(pTemp);
+ if ( !pFanin->fMarkA )
+ {
+ pFanin->fMarkA = 1;
+ Vec_PtrPush( vNodes, pFanin );
+ }
+ }
+ // remember the number of nodes in the frontier
+ nNodes = Vec_PtrSize( vNodes );
+ // add the remaining nodes
+ Vec_PtrForEachEntry( vFront, pTemp, i )
+ Vec_PtrPush( vNodes, pTemp );
+ // unmark the nodes
+ Vec_PtrForEachEntry( vNodes, pTemp, i )
+ {
+ pTemp->fMarkA = 0;
+ pTemp->TravId = i;
+ }
+ // collect the frontier nodes
+ Vec_PtrClear( vFront );
+ Vec_PtrForEachEntryStop( vNodes, pTemp, i, nNodes )
+ Vec_PtrPush( vFront, pTemp );
+// printf( "%d ", Vec_PtrSize(vNodes) );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeComputeVolume2( Ivy_Obj_t * pObj, int nNodeLimit, Vec_Ptr_t * vNodes, Vec_Ptr_t * vFront )
+{
+ Ivy_Obj_t * pLeaf, * pPivot, * pFanin;
+ int LevelMax, i;
+ assert( Ivy_ObjIsNode(pObj) );
+ // clear arrays
+ Vec_PtrClear( vNodes );
+ Vec_PtrClear( vFront );
+ // add the root
+ pObj->fMarkA = 1;
+ Vec_PtrPush( vNodes, pObj );
+ Vec_PtrPush( vFront, pObj );
+ // expand node with maximum level
+ LevelMax = pObj->Level;
+ do {
+ // get the node to expand
+ pPivot = NULL;
+ Vec_PtrForEachEntryReverse( vFront, pLeaf, i )
+ {
+ if ( (int)pLeaf->Level == LevelMax )
+ {
+ pPivot = pLeaf;
+ break;
+ }
+ }
+ // decrease level if we did not find the node
+ if ( pPivot == NULL )
+ {
+ if ( --LevelMax == 0 )
+ break;
+ continue;
+ }
+ // the node to expand is found
+ // remove it from frontier
+ Vec_PtrRemove( vFront, pPivot );
+ // add fanins
+ pFanin = Ivy_ObjFanin0(pPivot);
+ if ( !pFanin->fMarkA )
+ {
+ pFanin->fMarkA = 1;
+ Vec_PtrPush( vNodes, pFanin );
+ Vec_PtrPush( vFront, pFanin );
+ }
+ pFanin = Ivy_ObjFanin1(pPivot);
+ if ( pFanin && !pFanin->fMarkA )
+ {
+ pFanin->fMarkA = 1;
+ Vec_PtrPush( vNodes, pFanin );
+ Vec_PtrPush( vFront, pFanin );
+ }
+ // quit if we collected enough nodes
+ } while ( Vec_PtrSize(vNodes) < nNodeLimit );
+
+ // sort nodes by level
+ Vec_PtrSort( vNodes, Ivy_CompareNodesByLevel );
+ // make sure the nodes are ordered in the increasing number of levels
+ pFanin = Vec_PtrEntry( vNodes, 0 );
+ pPivot = Vec_PtrEntryLast( vNodes );
+ assert( pFanin->Level <= pPivot->Level );
+
+ // clean the marks and remember node numbers in the TravId
+ Vec_PtrForEachEntry( vNodes, pFanin, i )
+ {
+ pFanin->fMarkA = 0;
+ pFanin->TravId = i;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Extra_TruthOrWords( unsigned * pOut, unsigned * pIn0, unsigned * pIn1, int nWords )
+{
+ int w;
+ for ( w = nWords-1; w >= 0; w-- )
+ pOut[w] = pIn0[w] | pIn1[w];
+}
+static inline int Extra_TruthIsImplyWords( unsigned * pIn1, unsigned * pIn2, int nWords )
+{
+ int w;
+ for ( w = nWords-1; w >= 0; w-- )
+ if ( pIn1[w] & ~pIn2[w] )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Merges two sets of bit-cuts at a node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeFindCutsMerge( Vec_Ptr_t * vCuts0, Vec_Ptr_t * vCuts1, Vec_Ptr_t * vCuts,
+ int nLeaves, int nWords, Vec_Int_t * vStore )
+{
+ unsigned * pBitCut, * pBitCut0, * pBitCut1, * pBitCutTest;
+ int i, k, c, w, Counter;
+ // iterate through the cut pairs
+ Vec_PtrForEachEntry( vCuts0, pBitCut0, i )
+ Vec_PtrForEachEntry( vCuts1, pBitCut1, k )
+ {
+ // skip infeasible cuts
+ Counter = 0;
+ for ( w = 0; w < nWords; w++ )
+ {
+ Counter += Extra_WordCountOnes( pBitCut0[w] | pBitCut1[w] );
+ if ( Counter > nLeaves )
+ break;
+ }
+ if ( Counter > nLeaves )
+ continue;
+ // the new cut is feasible - create it
+ pBitCutTest = Vec_IntFetch( vStore, nWords );
+ Extra_TruthOrWords( pBitCutTest, pBitCut0, pBitCut1, nWords );
+ // filter contained cuts; try to find containing cut
+ w = 0;
+ Vec_PtrForEachEntry( vCuts, pBitCut, c )
+ {
+ if ( Extra_TruthIsImplyWords( pBitCut, pBitCutTest, nWords ) )
+ break;
+ if ( Extra_TruthIsImplyWords( pBitCutTest, pBitCut, nWords ) )
+ continue;
+ Vec_PtrWriteEntry( vCuts, w++, pBitCut );
+ }
+ if ( c != Vec_PtrSize(vCuts) )
+ continue;
+ Vec_PtrShrink( vCuts, w );
+ // add the cut
+ Vec_PtrPush( vCuts, pBitCutTest );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compute the set of all cuts.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManTestCutsTravAll( Ivy_Man_t * p )
+{
+ Ivy_Store_t * pStore;
+ Ivy_Obj_t * pObj;
+ Vec_Ptr_t * vNodes, * vFront;
+ Vec_Int_t * vStore;
+ Vec_Vec_t * vBitCuts;
+ int i, nCutsCut, nCutsTotal, nNodeTotal, nNodeOver;
+ int clk = clock();
+
+ vNodes = Vec_PtrAlloc( 100 );
+ vFront = Vec_PtrAlloc( 100 );
+ vStore = Vec_IntAlloc( 100 );
+ vBitCuts = Vec_VecAlloc( 100 );
+
+ nNodeTotal = nNodeOver = 0;
+ nCutsTotal = -Ivy_ManNodeNum(p);
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ if ( !Ivy_ObjIsNode(pObj) )
+ continue;
+ pStore = Ivy_NodeFindCutsTravAll( p, pObj, 4, 60, vNodes, vFront, vStore, vBitCuts );
+ nCutsCut = pStore->nCuts;
+ nCutsTotal += nCutsCut;
+ nNodeOver += (nCutsCut == IVY_CUT_LIMIT);
+ nNodeTotal++;
+ }
+ printf( "Total cuts = %6d. Trivial = %6d. Nodes = %6d. Satur = %6d. ",
+ nCutsTotal, Ivy_ManPiNum(p) + Ivy_ManNodeNum(p), nNodeTotal, nNodeOver );
+ PRT( "Time", clock() - clk );
+
+ Vec_PtrFree( vNodes );
+ Vec_PtrFree( vFront );
+ Vec_IntFree( vStore );
+ Vec_VecFree( vBitCuts );
+
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyDfs.c b/src/aig/ivy/ivyDfs.c
new file mode 100644
index 00000000..c27cba31
--- /dev/null
+++ b/src/aig/ivy/ivyDfs.c
@@ -0,0 +1,493 @@
+/**CFile****************************************************************
+
+ FileName [ivyDfs.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [DFS collection procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyDfs.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Collects nodes in the DFS order.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManDfs_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, Vec_Int_t * vNodes )
+{
+ if ( Ivy_ObjIsMarkA(pObj) )
+ return;
+ Ivy_ObjSetMarkA(pObj);
+ if ( Ivy_ObjIsConst1(pObj) || Ivy_ObjIsCi(pObj) )
+ {
+ if ( p->pHaig == NULL && pObj->pEquiv )
+ Ivy_ManDfs_rec( p, Ivy_Regular(pObj->pEquiv), vNodes );
+ return;
+ }
+//printf( "visiting node %d\n", pObj->Id );
+/*
+ if ( pObj->Id == 87 || pObj->Id == 90 )
+ {
+ int y = 0;
+ }
+*/
+ assert( Ivy_ObjIsBuf(pObj) || Ivy_ObjIsAnd(pObj) || Ivy_ObjIsExor(pObj) );
+ Ivy_ManDfs_rec( p, Ivy_ObjFanin0(pObj), vNodes );
+ if ( !Ivy_ObjIsBuf(pObj) )
+ Ivy_ManDfs_rec( p, Ivy_ObjFanin1(pObj), vNodes );
+ if ( p->pHaig == NULL && pObj->pEquiv )
+ Ivy_ManDfs_rec( p, Ivy_Regular(pObj->pEquiv), vNodes );
+ Vec_IntPush( vNodes, pObj->Id );
+
+//printf( "adding node %d with fanins %d and %d and equiv %d (refs = %d)\n",
+// pObj->Id, Ivy_ObjFanin0(pObj)->Id, Ivy_ObjFanin1(pObj)->Id,
+// pObj->pEquiv? Ivy_Regular(pObj->pEquiv)->Id: -1, Ivy_ObjRefs(pObj) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects AND/EXOR nodes in the DFS order from CIs to COs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Int_t * Ivy_ManDfs( Ivy_Man_t * p )
+{
+ Vec_Int_t * vNodes;
+ Ivy_Obj_t * pObj;
+ int i;
+ assert( Ivy_ManLatchNum(p) == 0 );
+ // make sure the nodes are not marked
+ Ivy_ManForEachObj( p, pObj, i )
+ assert( !pObj->fMarkA && !pObj->fMarkB );
+ // collect the nodes
+ vNodes = Vec_IntAlloc( Ivy_ManNodeNum(p) );
+ Ivy_ManForEachPo( p, pObj, i )
+ Ivy_ManDfs_rec( p, Ivy_ObjFanin0(pObj), vNodes );
+ // unmark the collected nodes
+// Ivy_ManForEachNodeVec( p, vNodes, pObj, i )
+// Ivy_ObjClearMarkA(pObj);
+ Ivy_ManForEachObj( p, pObj, i )
+ Ivy_ObjClearMarkA(pObj);
+ // make sure network does not have dangling nodes
+ assert( Vec_IntSize(vNodes) == Ivy_ManNodeNum(p) + Ivy_ManBufNum(p) );
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects AND/EXOR nodes in the DFS order from CIs to COs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Int_t * Ivy_ManDfsSeq( Ivy_Man_t * p, Vec_Int_t ** pvLatches )
+{
+ Vec_Int_t * vNodes, * vLatches;
+ Ivy_Obj_t * pObj;
+ int i;
+// assert( Ivy_ManLatchNum(p) > 0 );
+ // make sure the nodes are not marked
+ Ivy_ManForEachObj( p, pObj, i )
+ assert( !pObj->fMarkA && !pObj->fMarkB );
+ // collect the latches
+ vLatches = Vec_IntAlloc( Ivy_ManLatchNum(p) );
+ Ivy_ManForEachLatch( p, pObj, i )
+ Vec_IntPush( vLatches, pObj->Id );
+ // collect the nodes
+ vNodes = Vec_IntAlloc( Ivy_ManNodeNum(p) );
+ Ivy_ManForEachPo( p, pObj, i )
+ Ivy_ManDfs_rec( p, Ivy_ObjFanin0(pObj), vNodes );
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ Ivy_ManDfs_rec( p, Ivy_ObjFanin0(pObj), vNodes );
+ // unmark the collected nodes
+// Ivy_ManForEachNodeVec( p, vNodes, pObj, i )
+// Ivy_ObjClearMarkA(pObj);
+ Ivy_ManForEachObj( p, pObj, i )
+ Ivy_ObjClearMarkA(pObj);
+ // make sure network does not have dangling nodes
+// assert( Vec_IntSize(vNodes) == Ivy_ManNodeNum(p) + Ivy_ManBufNum(p) );
+
+// temporary!!!
+
+ if ( pvLatches == NULL )
+ Vec_IntFree( vLatches );
+ else
+ *pvLatches = vLatches;
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects nodes in the cone.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCollectCone_rec( Ivy_Obj_t * pObj, Vec_Ptr_t * vCone )
+{
+ if ( pObj->fMarkA )
+ return;
+ if ( Ivy_ObjIsBuf(pObj) )
+ {
+ Ivy_ManCollectCone_rec( Ivy_ObjFanin0(pObj), vCone );
+ Vec_PtrPush( vCone, pObj );
+ return;
+ }
+ assert( Ivy_ObjIsNode(pObj) );
+ Ivy_ManCollectCone_rec( Ivy_ObjFanin0(pObj), vCone );
+ Ivy_ManCollectCone_rec( Ivy_ObjFanin1(pObj), vCone );
+ Vec_PtrPushUnique( vCone, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects nodes in the cone.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCollectCone( Ivy_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vCone )
+{
+ Ivy_Obj_t * pTemp;
+ int i;
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjIsNode(pObj) );
+ // mark the nodes
+ Vec_PtrForEachEntry( vFront, pTemp, i )
+ Ivy_Regular(pTemp)->fMarkA = 1;
+ assert( pObj->fMarkA == 0 );
+ // collect the cone
+ Vec_PtrClear( vCone );
+ Ivy_ManCollectCone_rec( pObj, vCone );
+ // unmark the nodes
+ Vec_PtrForEachEntry( vFront, pTemp, i )
+ Ivy_Regular(pTemp)->fMarkA = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the nodes by level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Vec_t * Ivy_ManLevelize( Ivy_Man_t * p )
+{
+ Vec_Vec_t * vNodes;
+ Ivy_Obj_t * pObj;
+ int i;
+ vNodes = Vec_VecAlloc( 100 );
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ assert( !Ivy_ObjIsBuf(pObj) );
+ if ( Ivy_ObjIsNode(pObj) )
+ Vec_VecPush( vNodes, pObj->Level, pObj );
+ }
+ return vNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes required levels for each node.]
+
+ Description [Assumes topological ordering of the nodes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Int_t * Ivy_ManRequiredLevels( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ Vec_Int_t * vLevelsR;
+ Vec_Vec_t * vNodes;
+ int i, k, Level, LevelMax;
+ assert( p->vRequired == NULL );
+ // start the required times
+ vLevelsR = Vec_IntStart( Ivy_ManObjIdMax(p) + 1 );
+ // iterate through the nodes in the reverse order
+ vNodes = Ivy_ManLevelize( p );
+ Vec_VecForEachEntryReverseReverse( vNodes, pObj, i, k )
+ {
+ Level = Vec_IntEntry( vLevelsR, pObj->Id ) + 1 + Ivy_ObjIsExor(pObj);
+ if ( Vec_IntEntry( vLevelsR, Ivy_ObjFaninId0(pObj) ) < Level )
+ Vec_IntWriteEntry( vLevelsR, Ivy_ObjFaninId0(pObj), Level );
+ if ( Vec_IntEntry( vLevelsR, Ivy_ObjFaninId1(pObj) ) < Level )
+ Vec_IntWriteEntry( vLevelsR, Ivy_ObjFaninId1(pObj), Level );
+ }
+ Vec_VecFree( vNodes );
+ // convert it into the required times
+ LevelMax = Ivy_ManLevels( p );
+//printf( "max %5d\n",LevelMax );
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ Level = Vec_IntEntry( vLevelsR, pObj->Id );
+ Vec_IntWriteEntry( vLevelsR, pObj->Id, LevelMax - Level );
+//printf( "%5d : %5d %5d\n", pObj->Id, Level, LevelMax - Level );
+ }
+ p->vRequired = vLevelsR;
+ return vLevelsR;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively detects combinational loops.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManIsAcyclic_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ // skip the node if it is already visited
+ if ( Ivy_ObjIsTravIdPrevious(p, pObj) )
+ return 1;
+ // check if the node is part of the combinational loop
+ if ( Ivy_ObjIsTravIdCurrent(p, pObj) )
+ {
+ fprintf( stdout, "Manager contains combinational loop!\n" );
+ fprintf( stdout, "Node \"%d\" is encountered twice on the following path:\n", Ivy_ObjId(pObj) );
+ fprintf( stdout, " %d", Ivy_ObjId(pObj) );
+ return 0;
+ }
+ // mark this node as a node on the current path
+ Ivy_ObjSetTravIdCurrent( p, pObj );
+ // explore equivalent nodes if pObj is the main node
+ if ( p->pHaig == NULL && pObj->pEquiv && Ivy_ObjRefs(pObj) > 0 )
+ {
+ Ivy_Obj_t * pTemp;
+ assert( !Ivy_IsComplement(pObj->pEquiv) );
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ {
+ // traverse the fanin's cone searching for the loop
+ if ( !Ivy_ManIsAcyclic_rec(p, pTemp) )
+ {
+ // return as soon as the loop is detected
+ fprintf( stdout, " -> (%d", Ivy_ObjId(pObj) );
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ fprintf( stdout, " %d", Ivy_ObjId(pTemp) );
+ fprintf( stdout, ")" );
+ return 0;
+ }
+ }
+ }
+ // quite if it is a CI node
+ if ( Ivy_ObjIsCi(pObj) || Ivy_ObjIsConst1(pObj) )
+ {
+ // mark this node as a visited node
+ Ivy_ObjSetTravIdPrevious( p, pObj );
+ return 1;
+ }
+ assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj) );
+ // traverse the fanin's cone searching for the loop
+ if ( !Ivy_ManIsAcyclic_rec(p, Ivy_ObjFanin0(pObj)) )
+ {
+ // return as soon as the loop is detected
+ fprintf( stdout, " -> %d", Ivy_ObjId(pObj) );
+ return 0;
+ }
+ // traverse the fanin's cone searching for the loop
+ if ( Ivy_ObjIsNode(pObj) && !Ivy_ManIsAcyclic_rec(p, Ivy_ObjFanin1(pObj)) )
+ {
+ // return as soon as the loop is detected
+ fprintf( stdout, " -> %d", Ivy_ObjId(pObj) );
+ return 0;
+ }
+ // mark this node as a visited node
+ Ivy_ObjSetTravIdPrevious( p, pObj );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Detects combinational loops.]
+
+ Description [This procedure is based on the idea suggested by Donald Chai.
+ As we traverse the network and visit the nodes, we need to distinquish
+ three types of nodes: (1) those that are visited for the first time,
+ (2) those that have been visited in this traversal but are currently not
+ on the traversal path, (3) those that have been visited and are currently
+ on the travesal path. When the node of type (3) is encountered, it means
+ that there is a combinational loop. To mark the three types of nodes,
+ two new values of the traversal IDs are used.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManIsAcyclic( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int fAcyclic, i;
+ // set the traversal ID for this DFS ordering
+ Ivy_ManIncrementTravId( p );
+ Ivy_ManIncrementTravId( p );
+ // pObj->TravId == pNet->nTravIds means "pObj is on the path"
+ // pObj->TravId == pNet->nTravIds - 1 means "pObj is visited but is not on the path"
+ // pObj->TravId < pNet->nTravIds - 1 means "pObj is not visited"
+ // traverse the network to detect cycles
+ fAcyclic = 1;
+ Ivy_ManForEachCo( p, pObj, i )
+ {
+ // traverse the output logic cone
+ if ( fAcyclic = Ivy_ManIsAcyclic_rec(p, Ivy_ObjFanin0(pObj)) )
+ continue;
+ // stop as soon as the first loop is detected
+ fprintf( stdout, " (cone of %s \"%d\")\n", Ivy_ObjIsLatch(pObj)? "latch" : "PO", Ivy_ObjId(pObj) );
+ break;
+ }
+ return fAcyclic;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the levels of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManSetLevels_rec( Ivy_Obj_t * pObj, int fHaig )
+{
+ // quit if the node is visited
+ if ( Ivy_ObjIsMarkA(pObj) )
+ return pObj->Level;
+ Ivy_ObjSetMarkA(pObj);
+ // quit if this is a CI
+ if ( Ivy_ObjIsConst1(pObj) || Ivy_ObjIsCi(pObj) )
+ return 0;
+ assert( Ivy_ObjIsBuf(pObj) || Ivy_ObjIsAnd(pObj) || Ivy_ObjIsExor(pObj) );
+ // get levels of the fanins
+ Ivy_ManSetLevels_rec( Ivy_ObjFanin0(pObj), fHaig );
+ if ( !Ivy_ObjIsBuf(pObj) )
+ Ivy_ManSetLevels_rec( Ivy_ObjFanin1(pObj), fHaig );
+ // get level of the node
+ if ( Ivy_ObjIsBuf(pObj) )
+ pObj->Level = 1 + Ivy_ObjFanin0(pObj)->Level;
+ else if ( Ivy_ObjIsNode(pObj) )
+ pObj->Level = Ivy_ObjLevelNew( pObj );
+ else assert( 0 );
+ // get level of other choices
+ if ( fHaig && pObj->pEquiv && Ivy_ObjRefs(pObj) > 0 )
+ {
+ Ivy_Obj_t * pTemp;
+ unsigned LevelMax = pObj->Level;
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ {
+ Ivy_ManSetLevels_rec( pTemp, fHaig );
+ LevelMax = IVY_MAX( LevelMax, pTemp->Level );
+ }
+ // get this level
+ pObj->Level = LevelMax;
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ pTemp->Level = LevelMax;
+ }
+ return pObj->Level;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the levels of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManSetLevels( Ivy_Man_t * p, int fHaig )
+{
+ Ivy_Obj_t * pObj;
+ int i, LevelMax;
+ // check if CIs have choices
+ if ( fHaig )
+ {
+ Ivy_ManForEachCi( p, pObj, i )
+ if ( pObj->pEquiv )
+ printf( "CI %d has a choice, which will not be visualized.\n", pObj->Id );
+ }
+ // clean the levels
+ Ivy_ManForEachObj( p, pObj, i )
+ pObj->Level = 0;
+ // compute the levels
+ LevelMax = 0;
+ Ivy_ManForEachCo( p, pObj, i )
+ {
+ Ivy_ManSetLevels_rec( Ivy_ObjFanin0(pObj), fHaig );
+ LevelMax = IVY_MAX( LevelMax, (int)Ivy_ObjFanin0(pObj)->Level );
+ }
+ // compute levels of nodes without fanout
+ Ivy_ManForEachObj( p, pObj, i )
+ if ( (Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj)) && Ivy_ObjRefs(pObj) == 0 )
+ {
+ Ivy_ManSetLevels_rec( pObj, fHaig );
+ LevelMax = IVY_MAX( LevelMax, (int)pObj->Level );
+ }
+ // clean the marks
+ Ivy_ManForEachObj( p, pObj, i )
+ Ivy_ObjClearMarkA(pObj);
+ return LevelMax;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyDsd.c b/src/aig/ivy/ivyDsd.c
new file mode 100644
index 00000000..3b8a2e68
--- /dev/null
+++ b/src/aig/ivy/ivyDsd.c
@@ -0,0 +1,819 @@
+/**CFile****************************************************************
+
+ FileName [ivyDsd.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Disjoint-support decomposition.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyDsd.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// decomposition types
+typedef enum {
+ IVY_DEC_PI, // 0: var
+ IVY_DEC_CONST1, // 1: CONST1
+ IVY_DEC_BUF, // 2: BUF
+ IVY_DEC_AND, // 3: AND
+ IVY_DEC_EXOR, // 4: EXOR
+ IVY_DEC_MUX, // 5: MUX
+ IVY_DEC_MAJ, // 6: MAJ
+ IVY_DEC_PRIME // 7: undecomposable
+} Ivy_DecType_t;
+
+typedef struct Ivy_Dec_t_ Ivy_Dec_t;
+struct Ivy_Dec_t_
+{
+ unsigned Type : 4; // the node type (PI, CONST1, AND, EXOR, MUX, PRIME)
+ unsigned fCompl : 1; // shows if node is complemented (root node only)
+ unsigned nFans : 3; // the number of fanins
+ unsigned Fan0 : 4; // fanin 0
+ unsigned Fan1 : 4; // fanin 1
+ unsigned Fan2 : 4; // fanin 2
+ unsigned Fan3 : 4; // fanin 3
+ unsigned Fan4 : 4; // fanin 4
+ unsigned Fan5 : 4; // fanin 5
+};
+
+static inline int Ivy_DecToInt( Ivy_Dec_t Node ) { return *((int *)&Node); }
+static inline Ivy_Dec_t Ivy_IntToDec( int Node ) { return *((Ivy_Dec_t *)&Node); }
+static inline void Ivy_DecClear( Ivy_Dec_t * pNode ) { *((int *)pNode) = 0; }
+
+
+static unsigned s_Masks[6][2] = {
+ { 0x55555555, 0xAAAAAAAA },
+ { 0x33333333, 0xCCCCCCCC },
+ { 0x0F0F0F0F, 0xF0F0F0F0 },
+ { 0x00FF00FF, 0xFF00FF00 },
+ { 0x0000FFFF, 0xFFFF0000 },
+ { 0x00000000, 0xFFFFFFFF }
+};
+
+static inline int Ivy_TruthWordCountOnes( unsigned uWord )
+{
+ uWord = (uWord & 0x55555555) + ((uWord>>1) & 0x55555555);
+ uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333);
+ uWord = (uWord & 0x0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F);
+ uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF);
+ return (uWord & 0x0000FFFF) + (uWord>>16);
+}
+
+static inline int Ivy_TruthCofactorIsConst( unsigned uTruth, int Var, int Cof, int Const )
+{
+ if ( Const == 0 )
+ return (uTruth & s_Masks[Var][Cof]) == 0;
+ else
+ return (uTruth & s_Masks[Var][Cof]) == s_Masks[Var][Cof];
+}
+
+static inline int Ivy_TruthCofactorIsOne( unsigned uTruth, int Var )
+{
+ return (uTruth & s_Masks[Var][0]) == 0;
+}
+
+static inline unsigned Ivy_TruthCofactor( unsigned uTruth, int Var )
+{
+ unsigned uCofactor = uTruth & s_Masks[Var >> 1][(Var & 1) == 0];
+ int Shift = (1 << (Var >> 1));
+ if ( Var & 1 )
+ return uCofactor | (uCofactor << Shift);
+ return uCofactor | (uCofactor >> Shift);
+}
+
+static inline unsigned Ivy_TruthCofactor2( unsigned uTruth, int Var0, int Var1 )
+{
+ return Ivy_TruthCofactor( Ivy_TruthCofactor(uTruth, Var0), Var1 );
+}
+
+// returns 1 if the truth table depends on this var (var is regular interger var)
+static inline int Ivy_TruthDepends( unsigned uTruth, int Var )
+{
+ return Ivy_TruthCofactor(uTruth, Var << 1) != Ivy_TruthCofactor(uTruth, (Var << 1) | 1);
+}
+
+static inline void Ivy_DecSetVar( Ivy_Dec_t * pNode, int iNum, unsigned Var )
+{
+ assert( iNum >= 0 && iNum <= 5 );
+ switch( iNum )
+ {
+ case 0: pNode->Fan0 = Var; break;
+ case 1: pNode->Fan1 = Var; break;
+ case 2: pNode->Fan2 = Var; break;
+ case 3: pNode->Fan3 = Var; break;
+ case 4: pNode->Fan4 = Var; break;
+ case 5: pNode->Fan5 = Var; break;
+ }
+}
+
+static inline unsigned Ivy_DecGetVar( Ivy_Dec_t * pNode, int iNum )
+{
+ assert( iNum >= 0 && iNum <= 5 );
+ switch( iNum )
+ {
+ case 0: return pNode->Fan0;
+ case 1: return pNode->Fan1;
+ case 2: return pNode->Fan2;
+ case 3: return pNode->Fan3;
+ case 4: return pNode->Fan4;
+ case 5: return pNode->Fan5;
+ }
+ return ~0;
+}
+
+static int Ivy_TruthDecompose_rec( unsigned uTruth, Vec_Int_t * vTree );
+static int Ivy_TruthRecognizeMuxMaj( unsigned uTruth, int * pSupp, int nSupp, Vec_Int_t * vTree );
+
+//int nTruthDsd;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Computes DSD of truth table of 5 variables or less.]
+
+ Description [Returns 1 if the function is a constant or is fully
+ DSD decomposable using AND/EXOR/MUX gates.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_TruthDsd( unsigned uTruth, Vec_Int_t * vTree )
+{
+ Ivy_Dec_t Node;
+ int i, RetValue;
+ // set the PI variables
+ Vec_IntClear( vTree );
+ for ( i = 0; i < 5; i++ )
+ Vec_IntPush( vTree, 0 );
+ // check if it is a constant
+ if ( uTruth == 0 || ~uTruth == 0 )
+ {
+ Ivy_DecClear( &Node );
+ Node.Type = IVY_DEC_CONST1;
+ Node.fCompl = (uTruth == 0);
+ Vec_IntPush( vTree, Ivy_DecToInt(Node) );
+ return 1;
+ }
+ // perform the decomposition
+ RetValue = Ivy_TruthDecompose_rec( uTruth, vTree );
+ if ( RetValue == -1 )
+ return 0;
+ // get the topmost node
+ if ( (RetValue >> 1) < 5 )
+ { // add buffer
+ Ivy_DecClear( &Node );
+ Node.Type = IVY_DEC_BUF;
+ Node.fCompl = (RetValue & 1);
+ Node.Fan0 = ((RetValue >> 1) << 1);
+ Vec_IntPush( vTree, Ivy_DecToInt(Node) );
+ }
+ else if ( RetValue & 1 )
+ { // check if the topmost node has to be complemented
+ Node = Ivy_IntToDec( Vec_IntPop(vTree) );
+ assert( Node.fCompl == 0 );
+ Node.fCompl = (RetValue & 1);
+ Vec_IntPush( vTree, Ivy_DecToInt(Node) );
+ }
+ if ( uTruth != Ivy_TruthDsdCompute(vTree) )
+ printf( "Verification failed.\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes DSD of truth table.]
+
+ Description [Returns the number of topmost decomposition node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_TruthDecompose_rec( unsigned uTruth, Vec_Int_t * vTree )
+{
+ Ivy_Dec_t Node;
+ int Supp[5], Vars0[5], Vars1[5], Vars2[5], * pVars;
+ int nSupp, Count0, Count1, Count2, nVars, RetValue, fCompl, i;
+ unsigned uTruthCof, uCof0, uCof1;
+
+ // get constant confactors
+ Count0 = Count1 = Count2 = nSupp = 0;
+ for ( i = 0; i < 5; i++ )
+ {
+ if ( Ivy_TruthCofactorIsConst(uTruth, i, 0, 0) )
+ Vars0[Count0++] = (i << 1) | 0;
+ else if ( Ivy_TruthCofactorIsConst(uTruth, i, 1, 0) )
+ Vars0[Count0++] = (i << 1) | 1;
+ else if ( Ivy_TruthCofactorIsConst(uTruth, i, 0, 1) )
+ Vars1[Count1++] = (i << 1) | 0;
+ else if ( Ivy_TruthCofactorIsConst(uTruth, i, 1, 1) )
+ Vars1[Count1++] = (i << 1) | 1;
+ else
+ {
+ uCof0 = Ivy_TruthCofactor( uTruth, (i << 1) | 1 );
+ uCof1 = Ivy_TruthCofactor( uTruth, (i << 1) | 0 );
+ if ( uCof0 == ~uCof1 )
+ Vars2[Count2++] = (i << 1) | 0;
+ else if ( uCof0 != uCof1 )
+ Supp[nSupp++] = i;
+ }
+ }
+ assert( Count0 == 0 || Count1 == 0 );
+ assert( Count0 == 0 || Count2 == 0 );
+ assert( Count1 == 0 || Count2 == 0 );
+
+ // consider the case of a single variable
+ if ( Count0 == 1 && nSupp == 0 )
+ return Vars0[0];
+
+ // consider more complex decompositions
+ if ( Count0 == 0 && Count1 == 0 && Count2 == 0 )
+ return Ivy_TruthRecognizeMuxMaj( uTruth, Supp, nSupp, vTree );
+
+ // extract the nodes
+ Ivy_DecClear( &Node );
+ if ( Count0 > 0 )
+ nVars = Count0, pVars = Vars0, Node.Type = IVY_DEC_AND, fCompl = 0;
+ else if ( Count1 > 0 )
+ nVars = Count1, pVars = Vars1, Node.Type = IVY_DEC_AND, fCompl = 1, uTruth = ~uTruth;
+ else if ( Count2 > 0 )
+ nVars = Count2, pVars = Vars2, Node.Type = IVY_DEC_EXOR, fCompl = 0;
+ else
+ assert( 0 );
+ Node.nFans = nVars+(nSupp>0);
+
+ // compute cofactor
+ uTruthCof = uTruth;
+ for ( i = 0; i < nVars; i++ )
+ {
+ uTruthCof = Ivy_TruthCofactor( uTruthCof, pVars[i] );
+ Ivy_DecSetVar( &Node, i, pVars[i] );
+ }
+
+ if ( Node.Type == IVY_DEC_EXOR )
+ fCompl ^= ((Node.nFans & 1) == 0);
+
+ if ( nSupp > 0 )
+ {
+ assert( uTruthCof != 0 && ~uTruthCof != 0 );
+ // call recursively
+ RetValue = Ivy_TruthDecompose_rec( uTruthCof, vTree );
+ // quit if non-decomposable
+ if ( RetValue == -1 )
+ return -1;
+ // remove the complement from the child if the node is EXOR
+ if ( Node.Type == IVY_DEC_EXOR && (RetValue & 1) )
+ {
+ fCompl ^= 1;
+ RetValue ^= 1;
+ }
+ // set the new decomposition
+ Ivy_DecSetVar( &Node, nVars, RetValue );
+ }
+ else if ( Node.Type == IVY_DEC_EXOR )
+ fCompl ^= (uTruthCof == 0);
+
+ Vec_IntPush( vTree, Ivy_DecToInt(Node) );
+ return ((Vec_IntSize(vTree)-1) << 1) | fCompl;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns a non-negative number if the truth table is a MUX.]
+
+ Description [If the truth table is a MUX, returns the variable as follows:
+ first, control variable; second, positive cofactor; third, negative cofactor.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_TruthRecognizeMuxMaj( unsigned uTruth, int * pSupp, int nSupp, Vec_Int_t * vTree )
+{
+ Ivy_Dec_t Node;
+ int i, k, RetValue0, RetValue1;
+ unsigned uCof0, uCof1, Num;
+ char Count[3];
+ assert( nSupp >= 3 );
+ // start the node
+ Ivy_DecClear( &Node );
+ Node.Type = IVY_DEC_MUX;
+ Node.nFans = 3;
+ // try each of the variables
+ for ( i = 0; i < nSupp; i++ )
+ {
+ // get the cofactors with respect to these variables
+ uCof0 = Ivy_TruthCofactor( uTruth, (pSupp[i] << 1) | 1 );
+ uCof1 = Ivy_TruthCofactor( uTruth, pSupp[i] << 1 );
+ // go through all other variables and make sure
+ // each of them belongs to the support of one cofactor
+ for ( k = 0; k < nSupp; k++ )
+ {
+ if ( k == i )
+ continue;
+ if ( Ivy_TruthDepends(uCof0, pSupp[k]) && Ivy_TruthDepends(uCof1, pSupp[k]) )
+ break;
+ }
+ if ( k < nSupp )
+ continue;
+ // MUX decomposition exists
+ RetValue0 = Ivy_TruthDecompose_rec( uCof0, vTree );
+ if ( RetValue0 == -1 )
+ break;
+ RetValue1 = Ivy_TruthDecompose_rec( uCof1, vTree );
+ if ( RetValue1 == -1 )
+ break;
+ // both of them exist; create the node
+ Ivy_DecSetVar( &Node, 0, pSupp[i] << 1 );
+ Ivy_DecSetVar( &Node, 1, RetValue1 );
+ Ivy_DecSetVar( &Node, 2, RetValue0 );
+ Vec_IntPush( vTree, Ivy_DecToInt(Node) );
+ return ((Vec_IntSize(vTree)-1) << 1) | 0;
+ }
+ // check majority gate
+ if ( nSupp > 3 )
+ return -1;
+ if ( Ivy_TruthWordCountOnes(uTruth) != 16 )
+ return -1;
+ // this is a majority gate; determine polarity
+ Node.Type = IVY_DEC_MAJ;
+ Count[0] = Count[1] = Count[2] = 0;
+ for ( i = 0; i < 8; i++ )
+ {
+ Num = 0;
+ for ( k = 0; k < 3; k++ )
+ if ( i & (1 << k) )
+ Num |= (1 << pSupp[k]);
+ assert( Num < 32 );
+ if ( (uTruth & (1 << Num)) == 0 )
+ continue;
+ for ( k = 0; k < 3; k++ )
+ if ( i & (1 << k) )
+ Count[k]++;
+ }
+ assert( Count[0] == 1 || Count[0] == 3 );
+ assert( Count[1] == 1 || Count[1] == 3 );
+ assert( Count[2] == 1 || Count[2] == 3 );
+ Ivy_DecSetVar( &Node, 0, (pSupp[0] << 1)|(Count[0] == 1) );
+ Ivy_DecSetVar( &Node, 1, (pSupp[1] << 1)|(Count[1] == 1) );
+ Ivy_DecSetVar( &Node, 2, (pSupp[2] << 1)|(Count[2] == 1) );
+ Vec_IntPush( vTree, Ivy_DecToInt(Node) );
+ return ((Vec_IntSize(vTree)-1) << 1) | 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes truth table of decomposition tree for verification.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_TruthDsdCompute_rec( int iNode, Vec_Int_t * vTree )
+{
+ unsigned uTruthChild, uTruthTotal;
+ int Var, i;
+ // get the node
+ Ivy_Dec_t Node = Ivy_IntToDec( Vec_IntEntry(vTree, iNode) );
+ // compute the node function
+ if ( Node.Type == IVY_DEC_CONST1 )
+ return s_Masks[5][ !Node.fCompl ];
+ if ( Node.Type == IVY_DEC_PI )
+ return s_Masks[iNode][ !Node.fCompl ];
+ if ( Node.Type == IVY_DEC_BUF )
+ {
+ uTruthTotal = Ivy_TruthDsdCompute_rec( Node.Fan0 >> 1, vTree );
+ return Node.fCompl? ~uTruthTotal : uTruthTotal;
+ }
+ if ( Node.Type == IVY_DEC_AND )
+ {
+ uTruthTotal = s_Masks[5][1];
+ for ( i = 0; i < (int)Node.nFans; i++ )
+ {
+ Var = Ivy_DecGetVar( &Node, i );
+ uTruthChild = Ivy_TruthDsdCompute_rec( Var >> 1, vTree );
+ uTruthTotal = (Var & 1)? uTruthTotal & ~uTruthChild : uTruthTotal & uTruthChild;
+ }
+ return Node.fCompl? ~uTruthTotal : uTruthTotal;
+ }
+ if ( Node.Type == IVY_DEC_EXOR )
+ {
+ uTruthTotal = 0;
+ for ( i = 0; i < (int)Node.nFans; i++ )
+ {
+ Var = Ivy_DecGetVar( &Node, i );
+ uTruthTotal ^= Ivy_TruthDsdCompute_rec( Var >> 1, vTree );
+ assert( (Var & 1) == 0 );
+ }
+ return Node.fCompl? ~uTruthTotal : uTruthTotal;
+ }
+ assert( Node.fCompl == 0 );
+ if ( Node.Type == IVY_DEC_MUX || Node.Type == IVY_DEC_MAJ )
+ {
+ unsigned uTruthChildC, uTruthChild1, uTruthChild0;
+ int VarC, Var1, Var0;
+ VarC = Ivy_DecGetVar( &Node, 0 );
+ Var1 = Ivy_DecGetVar( &Node, 1 );
+ Var0 = Ivy_DecGetVar( &Node, 2 );
+ uTruthChildC = Ivy_TruthDsdCompute_rec( VarC >> 1, vTree );
+ uTruthChild1 = Ivy_TruthDsdCompute_rec( Var1 >> 1, vTree );
+ uTruthChild0 = Ivy_TruthDsdCompute_rec( Var0 >> 1, vTree );
+ assert( Node.Type == IVY_DEC_MAJ || (VarC & 1) == 0 );
+ uTruthChildC = (VarC & 1)? ~uTruthChildC : uTruthChildC;
+ uTruthChild1 = (Var1 & 1)? ~uTruthChild1 : uTruthChild1;
+ uTruthChild0 = (Var0 & 1)? ~uTruthChild0 : uTruthChild0;
+ if ( Node.Type == IVY_DEC_MUX )
+ return (uTruthChildC & uTruthChild1) | (~uTruthChildC & uTruthChild0);
+ else
+ return (uTruthChildC & uTruthChild1) | (uTruthChildC & uTruthChild0) | (uTruthChild1 & uTruthChild0);
+ }
+ assert( 0 );
+ return 0;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes truth table of decomposition tree for verification.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_TruthDsdCompute( Vec_Int_t * vTree )
+{
+ return Ivy_TruthDsdCompute_rec( Vec_IntSize(vTree)-1, vTree );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints the decomposition tree.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthDsdPrint_rec( FILE * pFile, int iNode, Vec_Int_t * vTree )
+{
+ int Var, i;
+ // get the node
+ Ivy_Dec_t Node = Ivy_IntToDec( Vec_IntEntry(vTree, iNode) );
+ // compute the node function
+ if ( Node.Type == IVY_DEC_CONST1 )
+ fprintf( pFile, "Const1%s", (Node.fCompl? "\'" : "") );
+ else if ( Node.Type == IVY_DEC_PI )
+ fprintf( pFile, "%c%s", 'a' + iNode, (Node.fCompl? "\'" : "") );
+ else if ( Node.Type == IVY_DEC_BUF )
+ {
+ Ivy_TruthDsdPrint_rec( pFile, Node.Fan0 >> 1, vTree );
+ fprintf( pFile, "%s", (Node.fCompl? "\'" : "") );
+ }
+ else if ( Node.Type == IVY_DEC_AND )
+ {
+ fprintf( pFile, "AND(" );
+ for ( i = 0; i < (int)Node.nFans; i++ )
+ {
+ Var = Ivy_DecGetVar( &Node, i );
+ Ivy_TruthDsdPrint_rec( pFile, Var >> 1, vTree );
+ fprintf( pFile, "%s", (Var & 1)? "\'" : "" );
+ if ( i != (int)Node.nFans-1 )
+ fprintf( pFile, "," );
+ }
+ fprintf( pFile, ")%s", (Node.fCompl? "\'" : "") );
+ }
+ else if ( Node.Type == IVY_DEC_EXOR )
+ {
+ fprintf( pFile, "EXOR(" );
+ for ( i = 0; i < (int)Node.nFans; i++ )
+ {
+ Var = Ivy_DecGetVar( &Node, i );
+ Ivy_TruthDsdPrint_rec( pFile, Var >> 1, vTree );
+ if ( i != (int)Node.nFans-1 )
+ fprintf( pFile, "," );
+ assert( (Var & 1) == 0 );
+ }
+ fprintf( pFile, ")%s", (Node.fCompl? "\'" : "") );
+ }
+ else if ( Node.Type == IVY_DEC_MUX || Node.Type == IVY_DEC_MAJ )
+ {
+ int VarC, Var1, Var0;
+ assert( Node.fCompl == 0 );
+ VarC = Ivy_DecGetVar( &Node, 0 );
+ Var1 = Ivy_DecGetVar( &Node, 1 );
+ Var0 = Ivy_DecGetVar( &Node, 2 );
+ fprintf( pFile, "%s", (Node.Type == IVY_DEC_MUX)? "MUX(" : "MAJ(" );
+ Ivy_TruthDsdPrint_rec( pFile, VarC >> 1, vTree );
+ fprintf( pFile, "%s", (VarC & 1)? "\'" : "" );
+ fprintf( pFile, "," );
+ Ivy_TruthDsdPrint_rec( pFile, Var1 >> 1, vTree );
+ fprintf( pFile, "%s", (Var1 & 1)? "\'" : "" );
+ fprintf( pFile, "," );
+ Ivy_TruthDsdPrint_rec( pFile, Var0 >> 1, vTree );
+ fprintf( pFile, "%s", (Var0 & 1)? "\'" : "" );
+ fprintf( pFile, ")" );
+ }
+ else assert( 0 );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints the decomposition tree.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthDsdPrint( FILE * pFile, Vec_Int_t * vTree )
+{
+ fprintf( pFile, "F = " );
+ Ivy_TruthDsdPrint_rec( pFile, Vec_IntSize(vTree)-1, vTree );
+ fprintf( pFile, "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implement DSD in the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ManDsdConstruct_rec( Ivy_Man_t * p, Vec_Int_t * vFront, int iNode, Vec_Int_t * vTree )
+{
+ Ivy_Obj_t * pResult, * pChild, * pNodes[16];
+ int Var, i;
+ // get the node
+ Ivy_Dec_t Node = Ivy_IntToDec( Vec_IntEntry(vTree, iNode) );
+ // compute the node function
+ if ( Node.Type == IVY_DEC_CONST1 )
+ return Ivy_NotCond( Ivy_ManConst1(p), Node.fCompl );
+ if ( Node.Type == IVY_DEC_PI )
+ {
+ pResult = Ivy_ManObj( p, Vec_IntEntry(vFront, iNode) );
+ return Ivy_NotCond( pResult, Node.fCompl );
+ }
+ if ( Node.Type == IVY_DEC_BUF )
+ {
+ pResult = Ivy_ManDsdConstruct_rec( p, vFront, Node.Fan0 >> 1, vTree );
+ return Ivy_NotCond( pResult, Node.fCompl );
+ }
+ if ( Node.Type == IVY_DEC_AND || Node.Type == IVY_DEC_EXOR )
+ {
+ for ( i = 0; i < (int)Node.nFans; i++ )
+ {
+ Var = Ivy_DecGetVar( &Node, i );
+ assert( Node.Type == IVY_DEC_AND || (Var & 1) == 0 );
+ pChild = Ivy_ManDsdConstruct_rec( p, vFront, Var >> 1, vTree );
+ pChild = Ivy_NotCond( pChild, (Var & 1) );
+ pNodes[i] = pChild;
+ }
+
+// Ivy_MultiEval( pNodes, Node.nFans, Node.Type == IVY_DEC_AND ? IVY_AND : IVY_EXOR );
+
+ pResult = Ivy_Multi( p, pNodes, Node.nFans, Node.Type == IVY_DEC_AND ? IVY_AND : IVY_EXOR );
+ return Ivy_NotCond( pResult, Node.fCompl );
+ }
+ assert( Node.fCompl == 0 );
+ if ( Node.Type == IVY_DEC_MUX || Node.Type == IVY_DEC_MAJ )
+ {
+ int VarC, Var1, Var0;
+ VarC = Ivy_DecGetVar( &Node, 0 );
+ Var1 = Ivy_DecGetVar( &Node, 1 );
+ Var0 = Ivy_DecGetVar( &Node, 2 );
+ pNodes[0] = Ivy_ManDsdConstruct_rec( p, vFront, VarC >> 1, vTree );
+ pNodes[1] = Ivy_ManDsdConstruct_rec( p, vFront, Var1 >> 1, vTree );
+ pNodes[2] = Ivy_ManDsdConstruct_rec( p, vFront, Var0 >> 1, vTree );
+ assert( Node.Type == IVY_DEC_MAJ || (VarC & 1) == 0 );
+ pNodes[0] = Ivy_NotCond( pNodes[0], (VarC & 1) );
+ pNodes[1] = Ivy_NotCond( pNodes[1], (Var1 & 1) );
+ pNodes[2] = Ivy_NotCond( pNodes[2], (Var0 & 1) );
+ if ( Node.Type == IVY_DEC_MUX )
+ return Ivy_Mux( p, pNodes[0], pNodes[1], pNodes[2] );
+ else
+ return Ivy_Maj( p, pNodes[0], pNodes[1], pNodes[2] );
+ }
+ assert( 0 );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implement DSD in the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ManDsdConstruct( Ivy_Man_t * p, Vec_Int_t * vFront, Vec_Int_t * vTree )
+{
+ int Entry, i;
+ // implement latches on the frontier (TEMPORARY!!!)
+ Vec_IntForEachEntry( vFront, Entry, i )
+ Vec_IntWriteEntry( vFront, i, Ivy_LeafId(Entry) );
+ // recursively construct the tree
+ return Ivy_ManDsdConstruct_rec( p, vFront, Vec_IntSize(vTree)-1, vTree );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthDsdComputePrint( unsigned uTruth )
+{
+ static Vec_Int_t * vTree = NULL;
+ if ( vTree == NULL )
+ vTree = Vec_IntAlloc( 12 );
+ if ( Ivy_TruthDsd( uTruth, vTree ) )
+ Ivy_TruthDsdPrint( stdout, vTree );
+ else
+ printf( "Undecomposable\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthTestOne( unsigned uTruth )
+{
+ static int Counter = 0;
+ static Vec_Int_t * vTree = NULL;
+ // decompose
+ if ( vTree == NULL )
+ vTree = Vec_IntAlloc( 12 );
+
+ if ( !Ivy_TruthDsd( uTruth, vTree ) )
+ {
+// printf( "Undecomposable\n" );
+ }
+ else
+ {
+// nTruthDsd++;
+ printf( "%5d : ", Counter++ );
+ Extra_PrintBinary( stdout, &uTruth, 32 );
+ printf( " " );
+ Ivy_TruthDsdPrint( stdout, vTree );
+ if ( uTruth != Ivy_TruthDsdCompute(vTree) )
+ printf( "Verification failed.\n" );
+ }
+// Vec_IntFree( vTree );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthTest()
+{
+ FILE * pFile;
+ char Buffer[100];
+ unsigned uTruth;
+ int i;
+
+ pFile = fopen( "npn4.txt", "r" );
+ for ( i = 0; i < 222; i++ )
+// pFile = fopen( "npn5.txt", "r" );
+// for ( i = 0; i < 616126; i++ )
+ {
+ fscanf( pFile, "%s", Buffer );
+ Extra_ReadHexadecimal( &uTruth, Buffer+2, 4 );
+// Extra_ReadHexadecimal( &uTruth, Buffer+2, 5 );
+ uTruth |= (uTruth << 16);
+// uTruth = ~uTruth;
+ Ivy_TruthTestOne( uTruth );
+ }
+ fclose( pFile );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthTest3()
+{
+ FILE * pFile;
+ char Buffer[100];
+ unsigned uTruth;
+ int i;
+
+ pFile = fopen( "npn3.txt", "r" );
+ for ( i = 0; i < 14; i++ )
+ {
+ fscanf( pFile, "%s", Buffer );
+ Extra_ReadHexadecimal( &uTruth, Buffer+2, 3 );
+ uTruth = uTruth | (uTruth << 8) | (uTruth << 16) | (uTruth << 24);
+ Ivy_TruthTestOne( uTruth );
+ }
+ fclose( pFile );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TruthTest5()
+{
+ FILE * pFile;
+ char Buffer[100];
+ unsigned uTruth;
+ int i;
+
+// pFile = fopen( "npn4.txt", "r" );
+// for ( i = 0; i < 222; i++ )
+ pFile = fopen( "npn5.txt", "r" );
+ for ( i = 0; i < 616126; i++ )
+ {
+ fscanf( pFile, "%s", Buffer );
+// Extra_ReadHexadecimal( &uTruth, Buffer+2, 4 );
+ Extra_ReadHexadecimal( &uTruth, Buffer+2, 5 );
+// uTruth |= (uTruth << 16);
+// uTruth = ~uTruth;
+ Ivy_TruthTestOne( uTruth );
+ }
+ fclose( pFile );
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyFanout.c b/src/aig/ivy/ivyFanout.c
new file mode 100644
index 00000000..3930186a
--- /dev/null
+++ b/src/aig/ivy/ivyFanout.c
@@ -0,0 +1,309 @@
+/**CFile****************************************************************
+
+ FileName [ivyFanout.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Representation of the fanouts.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyFanout.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// 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 ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the fanout representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManStartFanout( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ assert( !p->fFanout );
+ p->fFanout = 1;
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ if ( Ivy_ObjFanin0(pObj) )
+ Ivy_ObjAddFanout( p, Ivy_ObjFanin0(pObj), pObj );
+ if ( Ivy_ObjFanin1(pObj) )
+ Ivy_ObjAddFanout( p, Ivy_ObjFanin1(pObj), pObj );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the fanout representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManStopFanout( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ assert( p->fFanout );
+ p->fFanout = 0;
+ Ivy_ManForEachObj( p, pObj, i )
+ pObj->pFanout = pObj->pNextFan0 = pObj->pNextFan1 = pObj->pPrevFan0 = pObj->pPrevFan1 = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Add the fanout.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjAddFanout( Ivy_Man_t * p, Ivy_Obj_t * pFanin, Ivy_Obj_t * pFanout )
+{
+ assert( p->fFanout );
+ if ( pFanin->pFanout )
+ {
+ *Ivy_ObjNextFanoutPlace(pFanin, pFanout) = pFanin->pFanout;
+ *Ivy_ObjPrevFanoutPlace(pFanin, pFanin->pFanout) = pFanout;
+ }
+ pFanin->pFanout = pFanout;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes the fanout.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjDeleteFanout( Ivy_Man_t * p, Ivy_Obj_t * pFanin, Ivy_Obj_t * pFanout )
+{
+ 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*************************************************************
+
+ Synopsis [Replaces the fanout of pOld to be pFanoutNew.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjPatchFanout( Ivy_Man_t * p, Ivy_Obj_t * pFanin, Ivy_Obj_t * pFanoutOld, Ivy_Obj_t * 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*************************************************************
+
+ Synopsis [Starts iteration through the fanouts.]
+
+ Description [Copies the currently available fanouts into the array.]
+
+ SideEffects [Can be used while the fanouts are being removed.]
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjCollectFanouts( Ivy_Man_t * p, Ivy_Obj_t * pObj, Vec_Ptr_t * vArray )
+{
+ Ivy_Obj_t * pFanout;
+ assert( p->fFanout );
+ assert( !Ivy_IsComplement(pObj) );
+ Vec_PtrClear( vArray );
+ Ivy_ObjForEachFanoutInt( pObj, pFanout )
+ Vec_PtrPush( vArray, pFanout );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads one fanout.]
+
+ Description [Returns fanout if there is only one fanout.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ObjReadFirstFanout( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ return pObj->pFanout;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reads one fanout.]
+
+ Description [Returns fanout if there is only one fanout.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ObjFanoutNum( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pFanout;
+ int Counter = 0;
+ Ivy_ObjForEachFanoutInt( pObj, pFanout )
+ Counter++;
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyFastMap.c b/src/aig/ivy/ivyFastMap.c
new file mode 100644
index 00000000..c4a043f2
--- /dev/null
+++ b/src/aig/ivy/ivyFastMap.c
@@ -0,0 +1,1593 @@
+/**CFile****************************************************************
+
+ FileName [ivyFastMap.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Fast FPGA mapping.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyFastMap.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define IVY_INFINITY 10000
+
+typedef struct Ivy_SuppMan_t_ Ivy_SuppMan_t;
+struct Ivy_SuppMan_t_
+{
+ int nLimit; // the limit on the number of inputs
+ int nObjs; // the number of entries
+ int nSize; // size of each entry in bytes
+ char * pMem; // memory allocated
+ Vec_Vec_t * vLuts; // the array of nodes used in the mapping
+};
+
+typedef struct Ivy_Supp_t_ Ivy_Supp_t;
+struct Ivy_Supp_t_
+{
+ char nSize; // the number of support nodes
+ char fMark; // multipurpose mask
+ char fMark2; // multipurpose mask
+ char fMark3; // multipurpose mask
+ int nRefs; // the number of references
+ short Delay; // the delay of the node
+ short DelayR; // the reverse delay of the node
+ int pArray[0]; // the support nodes
+};
+
+static inline Ivy_Supp_t * Ivy_ObjSupp( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ return (Ivy_Supp_t *)(((Ivy_SuppMan_t*)pAig->pData)->pMem + pObj->Id * ((Ivy_SuppMan_t*)pAig->pData)->nSize);
+}
+static inline Ivy_Supp_t * Ivy_ObjSuppStart( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSupp;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ pSupp->fMark = 0;
+ pSupp->Delay = 0;
+ pSupp->nSize = 1;
+ pSupp->pArray[0] = pObj->Id;
+ return pSupp;
+}
+
+static void Ivy_FastMapPrint( Ivy_Man_t * pAig, int Delay, int Area, int Time, char * pStr );
+static int Ivy_FastMapDelay( Ivy_Man_t * pAig );
+static int Ivy_FastMapArea( Ivy_Man_t * pAig );
+static void Ivy_FastMapNode( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit );
+static void Ivy_FastMapNodeArea( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit );
+static int Ivy_FastMapMerge( Ivy_Supp_t * pSupp0, Ivy_Supp_t * pSupp1, Ivy_Supp_t * pSupp, int nLimit );
+static void Ivy_FastMapRequired( Ivy_Man_t * pAig, int Delay, int fSetInter );
+static void Ivy_FastMapRecover( Ivy_Man_t * pAig, int nLimit );
+static int Ivy_FastMapNodeDelay( Ivy_Man_t * pAig, Ivy_Obj_t * pObj );
+static int Ivy_FastMapNodeAreaRefed( Ivy_Man_t * pAig, Ivy_Obj_t * pObj );
+static int Ivy_FastMapNodeAreaDerefed( Ivy_Man_t * pAig, Ivy_Obj_t * pObj );
+static void Ivy_FastMapNodeRecover( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld );
+static int Ivy_FastMapNodeRef( Ivy_Man_t * pAig, Ivy_Obj_t * pObj );
+static int Ivy_FastMapNodeDeref( Ivy_Man_t * pAig, Ivy_Obj_t * pObj );
+
+
+extern int s_MappingTime;
+extern int s_MappingMem;
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast K-LUT mapping of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapPerform( Ivy_Man_t * pAig, int nLimit, int fRecovery, int fVerbose )
+{
+ Ivy_SuppMan_t * pMan;
+ Ivy_Obj_t * pObj;
+ int i, Delay, Area, clk, clkTotal = clock();
+ // start the memory for supports
+ pMan = ALLOC( Ivy_SuppMan_t, 1 );
+ memset( pMan, 0, sizeof(Ivy_SuppMan_t) );
+ pMan->nLimit = nLimit;
+ pMan->nObjs = Ivy_ManObjIdMax(pAig) + 1;
+ pMan->nSize = sizeof(Ivy_Supp_t) + nLimit * sizeof(int);
+ pMan->pMem = (char *)malloc( pMan->nObjs * pMan->nSize );
+ memset( pMan->pMem, 0, pMan->nObjs * pMan->nSize );
+ pMan->vLuts = Vec_VecAlloc( 100 );
+ pAig->pData = pMan;
+clk = clock();
+ // set the PI mapping
+ Ivy_ObjSuppStart( pAig, Ivy_ManConst1(pAig) );
+ Ivy_ManForEachPi( pAig, pObj, i )
+ Ivy_ObjSuppStart( pAig, pObj );
+ // iterate through all nodes in the topological order
+ Ivy_ManForEachNode( pAig, pObj, i )
+ Ivy_FastMapNode( pAig, pObj, nLimit );
+ // find the best arrival time and area
+ Delay = Ivy_FastMapDelay( pAig );
+ Area = Ivy_FastMapArea(pAig);
+ if ( fVerbose )
+ Ivy_FastMapPrint( pAig, Delay, Area, clock() - clk, "Delay oriented mapping: " );
+
+// 2-1-2 (doing 2-1-2-1-2 improves 0.5%)
+
+ if ( fRecovery )
+ {
+clk = clock();
+ Ivy_FastMapRequired( pAig, Delay, 0 );
+ // remap the nodes
+ Ivy_FastMapRecover( pAig, nLimit );
+ Delay = Ivy_FastMapDelay( pAig );
+ Area = Ivy_FastMapArea(pAig);
+ if ( fVerbose )
+ Ivy_FastMapPrint( pAig, Delay, Area, clock() - clk, "Area recovery 2 : " );
+
+clk = clock();
+ Ivy_FastMapRequired( pAig, Delay, 0 );
+ // iterate through all nodes in the topological order
+ Ivy_ManForEachNode( pAig, pObj, i )
+ Ivy_FastMapNodeArea( pAig, pObj, nLimit );
+ Delay = Ivy_FastMapDelay( pAig );
+ Area = Ivy_FastMapArea(pAig);
+ if ( fVerbose )
+ Ivy_FastMapPrint( pAig, Delay, Area, clock() - clk, "Area recovery 1 : " );
+
+clk = clock();
+ Ivy_FastMapRequired( pAig, Delay, 0 );
+ // remap the nodes
+ Ivy_FastMapRecover( pAig, nLimit );
+ Delay = Ivy_FastMapDelay( pAig );
+ Area = Ivy_FastMapArea(pAig);
+ if ( fVerbose )
+ Ivy_FastMapPrint( pAig, Delay, Area, clock() - clk, "Area recovery 2 : " );
+ }
+
+
+ s_MappingTime = clock() - clkTotal;
+ s_MappingMem = pMan->nObjs * pMan->nSize;
+/*
+ {
+ Vec_Ptr_t * vNodes;
+ vNodes = Vec_PtrAlloc( 100 );
+ Vec_VecForEachEntry( pMan->vLuts, pObj, i, k )
+ Vec_PtrPush( vNodes, pObj );
+ Ivy_ManShow( pAig, 0, vNodes );
+ Vec_PtrFree( vNodes );
+ }
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Cleans memory used for decomposition.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapStop( Ivy_Man_t * pAig )
+{
+ Ivy_SuppMan_t * p = pAig->pData;
+ Vec_VecFree( p->vLuts );
+ free( p->pMem );
+ free( p );
+ pAig->pData = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints statistics.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapPrint( Ivy_Man_t * pAig, int Delay, int Area, int Time, char * pStr )
+{
+ printf( "%s : Delay = %3d. Area = %6d. ", pStr, Delay, Area );
+ PRT( "Time", Time );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes delay after LUT mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapDelay( Ivy_Man_t * pAig )
+{
+ Ivy_Supp_t * pSupp;
+ Ivy_Obj_t * pObj;
+ int i, DelayMax = 0;
+ Ivy_ManForEachPo( pAig, pObj, i )
+ {
+ pObj = Ivy_ObjFanin0(pObj);
+ if ( !Ivy_ObjIsNode(pObj) )
+ continue;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ if ( DelayMax < pSupp->Delay )
+ DelayMax = pSupp->Delay;
+ }
+ return DelayMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes area after mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapArea_rec( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Vec_Vec_t * vLuts )
+{
+ Ivy_Supp_t * pSupp;
+ int i, Counter;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ // skip visited nodes and PIs
+ if ( pSupp->fMark || pSupp->nSize == 1 )
+ return 0;
+ pSupp->fMark = 1;
+ // compute the area of this node
+ Counter = 0;
+ for ( i = 0; i < pSupp->nSize; i++ )
+ Counter += Ivy_FastMapArea_rec( pAig, Ivy_ManObj(pAig, pSupp->pArray[i]), vLuts );
+ // add the node to the array of LUTs
+ Vec_VecPush( vLuts, pSupp->Delay, pObj );
+ return 1 + Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes area after mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapArea( Ivy_Man_t * pAig )
+{
+ Vec_Vec_t * vLuts;
+ Ivy_Obj_t * pObj;
+ int i, Counter = 0;
+ // get the array to store the nodes
+ vLuts = ((Ivy_SuppMan_t *)pAig->pData)->vLuts;
+ Vec_VecClear( vLuts );
+ // explore starting from each node
+ Ivy_ManForEachPo( pAig, pObj, i )
+ Counter += Ivy_FastMapArea_rec( pAig, Ivy_ObjFanin0(pObj), vLuts );
+ // clean the marks
+ Ivy_ManForEachNode( pAig, pObj, i )
+ Ivy_ObjSupp( pAig, pObj )->fMark = 0;
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Ivy_ObjIsNodeInt1( Ivy_Obj_t * pObj )
+{
+ return Ivy_ObjIsNode(pObj) && Ivy_ObjRefs(pObj) == 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Ivy_ObjIsNodeInt2( Ivy_Obj_t * pObj )
+{
+ return Ivy_ObjIsNode(pObj) && Ivy_ObjRefs(pObj) <= 2;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline void Vec_IntSelectSort( int * pArray, int nSize )
+{
+ int temp, i, j, best_i;
+ for ( i = 0; i < nSize-1; i++ )
+ {
+ best_i = i;
+ for ( j = i+1; j < nSize; j++ )
+ if ( pArray[j] < pArray[best_i] )
+ best_i = j;
+ temp = pArray[i];
+ pArray[i] = pArray[best_i];
+ pArray[best_i] = temp;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Vec_IntRemoveDup( int * pArray, int nSize )
+{
+ int i, k;
+ if ( nSize < 2 )
+ return nSize;
+ for ( i = k = 1; i < nSize; i++ )
+ if ( pArray[i] != pArray[i-1] )
+ pArray[k++] = pArray[i];
+ return k;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeArea2( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit )
+{
+ static int Store[32], StoreSize;
+ static char Supp0[16], Supp1[16];
+ static Ivy_Supp_t * pTemp0 = (Ivy_Supp_t *)Supp0;
+ static Ivy_Supp_t * pTemp1 = (Ivy_Supp_t *)Supp1;
+ Ivy_Obj_t * pFanin0, * pFanin1;
+ Ivy_Supp_t * pSupp0, * pSupp1, * pSupp;
+ int RetValue, DelayOld;
+ assert( nLimit <= 32 );
+ assert( Ivy_ObjIsNode(pObj) );
+ // get the fanins
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ // get the supports
+ pSupp0 = Ivy_ObjSupp( pAig, pFanin0 );
+ pSupp1 = Ivy_ObjSupp( pAig, pFanin1 );
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->fMark == 0 );
+ // get the old delay of the node
+ DelayOld = Ivy_FastMapNodeDelay(pAig, pObj);
+ assert( DelayOld <= pSupp->DelayR );
+ // copy the current cut
+ memcpy( Store, pSupp->pArray, sizeof(int) * pSupp->nSize );
+ StoreSize = pSupp->nSize;
+ // get the fanin support
+ if ( Ivy_ObjRefs(pFanin0) > 1 && pSupp0->Delay < pSupp->DelayR )
+ {
+ pSupp0 = pTemp0;
+ pSupp0->nSize = 1;
+ pSupp0->pArray[0] = Ivy_ObjFaninId0(pObj);
+ }
+ // get the fanin support
+ if ( Ivy_ObjRefs(pFanin1) > 1 && pSupp1->Delay < pSupp->DelayR )
+ {
+ pSupp1 = pTemp1;
+ pSupp1->nSize = 1;
+ pSupp1->pArray[0] = Ivy_ObjFaninId1(pObj);
+ }
+ // merge the cuts
+ if ( pSupp0->nSize < pSupp1->nSize )
+ RetValue = Ivy_FastMapMerge( pSupp1, pSupp0, pSupp, nLimit );
+ else
+ RetValue = Ivy_FastMapMerge( pSupp0, pSupp1, pSupp, nLimit );
+ if ( !RetValue )
+ {
+ pSupp->nSize = 2;
+ pSupp->pArray[0] = Ivy_ObjFaninId0(pObj);
+ pSupp->pArray[1] = Ivy_ObjFaninId1(pObj);
+ }
+ // check the resulting delay
+ pSupp->Delay = Ivy_FastMapNodeDelay(pAig, pObj);
+ if ( pSupp->Delay > pSupp->DelayR )
+ {
+ pSupp->nSize = StoreSize;
+ memcpy( pSupp->pArray, Store, sizeof(int) * pSupp->nSize );
+ pSupp->Delay = DelayOld;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeArea( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit )
+{
+ static int Store[32], StoreSize;
+ static char Supp0[16], Supp1[16];
+ static Ivy_Supp_t * pTemp0 = (Ivy_Supp_t *)Supp0;
+ static Ivy_Supp_t * pTemp1 = (Ivy_Supp_t *)Supp1;
+ Ivy_Obj_t * pFanin0, * pFanin1;
+ Ivy_Supp_t * pSupp0, * pSupp1, * pSupp;
+ int RetValue, DelayOld, RefsOld;
+ int AreaBef, AreaAft;
+ assert( nLimit <= 32 );
+ assert( Ivy_ObjIsNode(pObj) );
+ // get the fanins
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ // get the supports
+ pSupp0 = Ivy_ObjSupp( pAig, pFanin0 );
+ pSupp1 = Ivy_ObjSupp( pAig, pFanin1 );
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->fMark == 0 );
+
+ // get the area
+ if ( pSupp->nRefs == 0 )
+ AreaBef = Ivy_FastMapNodeAreaDerefed( pAig, pObj );
+ else
+ AreaBef = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+// if ( AreaBef == 1 )
+// return;
+
+ // deref the cut if the node is refed
+ if ( pSupp->nRefs != 0 )
+ Ivy_FastMapNodeDeref( pAig, pObj );
+
+ // get the old delay of the node
+ DelayOld = Ivy_FastMapNodeDelay(pAig, pObj);
+ assert( DelayOld <= pSupp->DelayR );
+ // copy the current cut
+ memcpy( Store, pSupp->pArray, sizeof(int) * pSupp->nSize );
+ StoreSize = pSupp->nSize;
+ // get the fanin support
+ if ( Ivy_ObjRefs(pFanin0) > 2 && pSupp0->Delay < pSupp->DelayR )
+// if ( pSupp0->nRefs > 0 && pSupp0->Delay < pSupp->DelayR ) // this leads to 2% worse results
+ {
+ pSupp0 = pTemp0;
+ pSupp0->nSize = 1;
+ pSupp0->pArray[0] = Ivy_ObjFaninId0(pObj);
+ }
+ // get the fanin support
+ if ( Ivy_ObjRefs(pFanin1) > 2 && pSupp1->Delay < pSupp->DelayR )
+// if ( pSupp1->nRefs > 0 && pSupp1->Delay < pSupp->DelayR )
+ {
+ pSupp1 = pTemp1;
+ pSupp1->nSize = 1;
+ pSupp1->pArray[0] = Ivy_ObjFaninId1(pObj);
+ }
+ // merge the cuts
+ if ( pSupp0->nSize < pSupp1->nSize )
+ RetValue = Ivy_FastMapMerge( pSupp1, pSupp0, pSupp, nLimit );
+ else
+ RetValue = Ivy_FastMapMerge( pSupp0, pSupp1, pSupp, nLimit );
+ if ( !RetValue )
+ {
+ pSupp->nSize = 2;
+ pSupp->pArray[0] = Ivy_ObjFaninId0(pObj);
+ pSupp->pArray[1] = Ivy_ObjFaninId1(pObj);
+ }
+
+ // check the resulting delay
+ pSupp->Delay = Ivy_FastMapNodeDelay(pAig, pObj);
+
+ RefsOld = pSupp->nRefs; pSupp->nRefs = 0;
+ AreaAft = Ivy_FastMapNodeAreaDerefed( pAig, pObj );
+ pSupp->nRefs = RefsOld;
+
+ if ( AreaAft > AreaBef || pSupp->Delay > pSupp->DelayR )
+// if ( pSupp->Delay > pSupp->DelayR )
+ {
+ pSupp->nSize = StoreSize;
+ memcpy( pSupp->pArray, Store, sizeof(int) * pSupp->nSize );
+ pSupp->Delay = DelayOld;
+// printf( "-" );
+ }
+// else
+// printf( "+" );
+
+ if ( pSupp->nRefs != 0 )
+ Ivy_FastMapNodeRef( pAig, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fast mapping for one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNode( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit )
+{
+ Ivy_Supp_t * pSupp0, * pSupp1, * pSupp;
+ int fFaninParam = 2;
+ int RetValue;
+ assert( Ivy_ObjIsNode(pObj) );
+ // get the supports
+ pSupp0 = Ivy_ObjSupp( pAig, Ivy_ObjFanin0(pObj) );
+ pSupp1 = Ivy_ObjSupp( pAig, Ivy_ObjFanin1(pObj) );
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ pSupp->fMark = 0;
+ // get the delays
+ if ( pSupp0->Delay == pSupp1->Delay )
+ pSupp->Delay = (pSupp0->Delay == 0) ? pSupp0->Delay + 1: pSupp0->Delay;
+ else if ( pSupp0->Delay > pSupp1->Delay )
+ {
+ pSupp->Delay = pSupp0->Delay;
+ pSupp1 = Ivy_ObjSupp( pAig, Ivy_ManConst1(pAig) );
+ pSupp1->pArray[0] = Ivy_ObjFaninId1(pObj);
+ }
+ else // if ( pSupp0->Delay < pSupp1->Delay )
+ {
+ pSupp->Delay = pSupp1->Delay;
+ pSupp0 = Ivy_ObjSupp( pAig, Ivy_ManConst1(pAig) );
+ pSupp0->pArray[0] = Ivy_ObjFaninId0(pObj);
+ }
+ // merge the cuts
+ if ( pSupp0->nSize < pSupp1->nSize )
+ RetValue = Ivy_FastMapMerge( pSupp1, pSupp0, pSupp, nLimit );
+ else
+ RetValue = Ivy_FastMapMerge( pSupp0, pSupp1, pSupp, nLimit );
+ if ( !RetValue )
+ {
+ pSupp->Delay++;
+ if ( fFaninParam == 2 )
+ {
+ pSupp->nSize = 2;
+ pSupp->pArray[0] = Ivy_ObjFaninId0(pObj);
+ pSupp->pArray[1] = Ivy_ObjFaninId1(pObj);
+ }
+ else if ( fFaninParam == 3 )
+ {
+ Ivy_Obj_t * pFanin0, * pFanin1, * pFaninA, * pFaninB;
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ pSupp->nSize = 0;
+ // process the first fanin
+ if ( Ivy_ObjIsNodeInt1(pFanin0) )
+ {
+ pFaninA = Ivy_ObjFanin0(pFanin0);
+ pFaninB = Ivy_ObjFanin1(pFanin0);
+ if ( Ivy_ObjIsNodeInt1(pFaninA) && Ivy_ObjIsNodeInt1(pFaninB) )
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin0);
+ else
+ {
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninA);
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninB);
+ }
+ }
+ else
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin0);
+ // process the second fanin
+ if ( Ivy_ObjIsNodeInt1(pFanin1) )
+ {
+ pFaninA = Ivy_ObjFanin0(pFanin1);
+ pFaninB = Ivy_ObjFanin1(pFanin1);
+ if ( Ivy_ObjIsNodeInt1(pFaninA) && Ivy_ObjIsNodeInt1(pFaninB) )
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin1);
+ else
+ {
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninA);
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninB);
+ }
+ }
+ else
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin1);
+ // sort the fanins
+ Vec_IntSelectSort( pSupp->pArray, pSupp->nSize );
+ pSupp->nSize = Vec_IntRemoveDup( pSupp->pArray, pSupp->nSize );
+ assert( pSupp->pArray[0] < pSupp->pArray[1] );
+ }
+ else if ( fFaninParam == 4 )
+ {
+ Ivy_Obj_t * pFanin0, * pFanin1, * pFaninA, * pFaninB;
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ pSupp->nSize = 0;
+ // consider the case when exactly one of them is internal
+ if ( Ivy_ObjIsNodeInt1(pFanin0) ^ Ivy_ObjIsNodeInt1(pFanin1) )
+ {
+ pSupp0 = Ivy_ObjSupp( pAig, Ivy_ObjFanin0(pObj) );
+ pSupp1 = Ivy_ObjSupp( pAig, Ivy_ObjFanin1(pObj) );
+ if ( Ivy_ObjIsNodeInt1(pFanin0) && pSupp0->nSize < nLimit )
+ {
+ pSupp->Delay = IVY_MAX( pSupp0->Delay, pSupp1->Delay + 1 );
+ pSupp1 = Ivy_ObjSupp( pAig, Ivy_ManConst1(pAig) );
+ pSupp1->pArray[0] = Ivy_ObjId(pFanin1);
+ // merge the cuts
+ RetValue = Ivy_FastMapMerge( pSupp0, pSupp1, pSupp, nLimit );
+ assert( RetValue );
+ assert( pSupp->nSize > 1 );
+ return;
+ }
+ if ( Ivy_ObjIsNodeInt1(pFanin1) && pSupp1->nSize < nLimit )
+ {
+ pSupp->Delay = IVY_MAX( pSupp1->Delay, pSupp0->Delay + 1 );
+ pSupp0 = Ivy_ObjSupp( pAig, Ivy_ManConst1(pAig) );
+ pSupp0->pArray[0] = Ivy_ObjId(pFanin0);
+ // merge the cuts
+ RetValue = Ivy_FastMapMerge( pSupp1, pSupp0, pSupp, nLimit );
+ assert( RetValue );
+ assert( pSupp->nSize > 1 );
+ return;
+ }
+ }
+ // process the first fanin
+ if ( Ivy_ObjIsNodeInt1(pFanin0) )
+ {
+ pFaninA = Ivy_ObjFanin0(pFanin0);
+ pFaninB = Ivy_ObjFanin1(pFanin0);
+ if ( Ivy_ObjIsNodeInt1(pFaninA) && Ivy_ObjIsNodeInt1(pFaninB) )
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin0);
+ else
+ {
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninA);
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninB);
+ }
+ }
+ else
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin0);
+ // process the second fanin
+ if ( Ivy_ObjIsNodeInt1(pFanin1) )
+ {
+ pFaninA = Ivy_ObjFanin0(pFanin1);
+ pFaninB = Ivy_ObjFanin1(pFanin1);
+ if ( Ivy_ObjIsNodeInt1(pFaninA) && Ivy_ObjIsNodeInt1(pFaninB) )
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin1);
+ else
+ {
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninA);
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFaninB);
+ }
+ }
+ else
+ pSupp->pArray[pSupp->nSize++] = Ivy_ObjId(pFanin1);
+ // sort the fanins
+ Vec_IntSelectSort( pSupp->pArray, pSupp->nSize );
+ pSupp->nSize = Vec_IntRemoveDup( pSupp->pArray, pSupp->nSize );
+ assert( pSupp->pArray[0] < pSupp->pArray[1] );
+ assert( pSupp->nSize > 1 );
+ }
+ }
+ assert( pSupp->Delay > 0 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Merges two supports]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapMerge( Ivy_Supp_t * pSupp0, Ivy_Supp_t * pSupp1, Ivy_Supp_t * pSupp, int nLimit )
+{
+ int i, k, c;
+ assert( pSupp0->nSize >= pSupp1->nSize );
+ // the case of the largest cut sizes
+ if ( pSupp0->nSize == nLimit && pSupp1->nSize == nLimit )
+ {
+ for ( i = 0; i < pSupp0->nSize; i++ )
+ if ( pSupp0->pArray[i] != pSupp1->pArray[i] )
+ return 0;
+ for ( i = 0; i < pSupp0->nSize; i++ )
+ pSupp->pArray[i] = pSupp0->pArray[i];
+ pSupp->nSize = pSupp0->nSize;
+ return 1;
+ }
+ // the case when one of the cuts is the largest
+ if ( pSupp0->nSize == nLimit )
+ {
+ for ( i = 0; i < pSupp1->nSize; i++ )
+ {
+ for ( k = pSupp0->nSize - 1; k >= 0; k-- )
+ if ( pSupp0->pArray[k] == pSupp1->pArray[i] )
+ break;
+ if ( k == -1 ) // did not find
+ return 0;
+ }
+ for ( i = 0; i < pSupp0->nSize; i++ )
+ pSupp->pArray[i] = pSupp0->pArray[i];
+ pSupp->nSize = pSupp0->nSize;
+ return 1;
+ }
+
+ // compare two cuts with different numbers
+ i = k = 0;
+ for ( c = 0; c < nLimit; c++ )
+ {
+ if ( k == pSupp1->nSize )
+ {
+ if ( i == pSupp0->nSize )
+ {
+ pSupp->nSize = c;
+ return 1;
+ }
+ pSupp->pArray[c] = pSupp0->pArray[i++];
+ continue;
+ }
+ if ( i == pSupp0->nSize )
+ {
+ if ( k == pSupp1->nSize )
+ {
+ pSupp->nSize = c;
+ return 1;
+ }
+ pSupp->pArray[c] = pSupp1->pArray[k++];
+ continue;
+ }
+ if ( pSupp0->pArray[i] < pSupp1->pArray[k] )
+ {
+ pSupp->pArray[c] = pSupp0->pArray[i++];
+ continue;
+ }
+ if ( pSupp0->pArray[i] > pSupp1->pArray[k] )
+ {
+ pSupp->pArray[c] = pSupp1->pArray[k++];
+ continue;
+ }
+ pSupp->pArray[c] = pSupp0->pArray[i++];
+ k++;
+ }
+ if ( i < pSupp0->nSize || k < pSupp1->nSize )
+ return 0;
+ pSupp->nSize = c;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates integer vector with the support of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapReadSupp( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Vec_Int_t * vLeaves )
+{
+ Ivy_Supp_t * pSupp;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ vLeaves->nCap = 8;
+ vLeaves->nSize = pSupp->nSize;
+ vLeaves->pArray = pSupp->pArray;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the required times of the intermediate nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapRequired_rec( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Ivy_Obj_t * pRoot, int DelayR )
+{
+ Ivy_Supp_t * pSupp;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ if ( pObj != pRoot && (pSupp->nRefs > 0 || Ivy_ObjIsCi(pObj)) )
+ return;
+ Ivy_FastMapRequired_rec( pAig, Ivy_ObjFanin0(pObj), pRoot, DelayR );
+ Ivy_FastMapRequired_rec( pAig, Ivy_ObjFanin1(pObj), pRoot, DelayR );
+// assert( pObj == pRoot || pSupp->DelayR == IVY_INFINITY );
+ pSupp->DelayR = DelayR;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the required times for each node.]
+
+ Description [Sets reference counters for each node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapRequired( Ivy_Man_t * pAig, int Delay, int fSetInter )
+{
+ Vec_Vec_t * vLuts;
+ Vec_Ptr_t * vNodes;
+ Ivy_Obj_t * pObj;
+ Ivy_Supp_t * pSupp, * pSuppF;
+ int i, k, c;
+ // clean the required times
+ Ivy_ManForEachPi( pAig, pObj, i )
+ {
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ pSupp->DelayR = IVY_INFINITY;
+ pSupp->nRefs = 0;
+ }
+ Ivy_ManForEachNode( pAig, pObj, i )
+ {
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ pSupp->DelayR = IVY_INFINITY;
+ pSupp->nRefs = 0;
+ }
+ // set the required times of the POs
+ Ivy_ManForEachPo( pAig, pObj, i )
+ {
+ pSupp = Ivy_ObjSupp( pAig, Ivy_ObjFanin0(pObj) );
+ pSupp->DelayR = Delay;
+ pSupp->nRefs++;
+ }
+ // get the levelized nodes used in the mapping
+ vLuts = ((Ivy_SuppMan_t *)pAig->pData)->vLuts;
+ // propagate the required times
+ Vec_VecForEachLevelReverse( vLuts, vNodes, i )
+ Vec_PtrForEachEntry( vNodes, pObj, k )
+ {
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->nRefs > 0 );
+ for ( c = 0; c < pSupp->nSize; c++ )
+ {
+ pSuppF = Ivy_ObjSupp( pAig, Ivy_ManObj(pAig, pSupp->pArray[c]) );
+ pSuppF->DelayR = IVY_MIN( pSuppF->DelayR, pSupp->DelayR - 1 );
+ pSuppF->nRefs++;
+ }
+ }
+/*
+ // print out some of the required times
+ Ivy_ManForEachPi( pAig, pObj, i )
+ {
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ printf( "%d ", pSupp->DelayR );
+ }
+ printf( "\n" );
+*/
+
+ if ( fSetInter )
+ {
+ // set the required times of the intermediate nodes
+ Vec_VecForEachLevelReverse( vLuts, vNodes, i )
+ Vec_PtrForEachEntry( vNodes, pObj, k )
+ {
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ Ivy_FastMapRequired_rec( pAig, pObj, pObj, pSupp->DelayR );
+ }
+ // make sure that all required times are assigned
+ Ivy_ManForEachNode( pAig, pObj, i )
+ {
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->DelayR < IVY_INFINITY );
+ }
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs area recovery for each node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapRecover( Ivy_Man_t * pAig, int nLimit )
+{
+ Vec_Ptr_t * vFront, * vFrontOld;
+ Ivy_Obj_t * pObj;
+ int i;
+ vFront = Vec_PtrAlloc( nLimit );
+ vFrontOld = Vec_PtrAlloc( nLimit );
+ Ivy_ManCleanTravId( pAig );
+ // iterate through all nodes in the topological order
+ Ivy_ManForEachNode( pAig, pObj, i )
+ Ivy_FastMapNodeRecover( pAig, pObj, nLimit, vFront, vFrontOld );
+ Vec_PtrFree( vFrontOld );
+ Vec_PtrFree( vFront );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the delay of the cut rooted at this node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeDelay( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSupp, * pSuppF;
+ int c, Delay = 0;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ for ( c = 0; c < pSupp->nSize; c++ )
+ {
+ pSuppF = Ivy_ObjSupp( pAig, Ivy_ManObj(pAig, pSupp->pArray[c]) );
+ Delay = IVY_MAX( Delay, pSuppF->Delay );
+ }
+ return 1 + Delay;
+}
+
+
+/**function*************************************************************
+
+ synopsis [References the cut.]
+
+ description [This procedure is similar to the procedure NodeReclaim.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+int Ivy_FastMapNodeRef( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSupp, * pSuppF;
+ Ivy_Obj_t * pNodeChild;
+ int aArea, i;
+ // start the area of this cut
+ aArea = 1;
+ // go through the children
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->nSize > 1 );
+ for ( i = 0; i < pSupp->nSize; i++ )
+ {
+ pNodeChild = Ivy_ManObj(pAig, pSupp->pArray[i]);
+ pSuppF = Ivy_ObjSupp( pAig, pNodeChild );
+ assert( pSuppF->nRefs >= 0 );
+ if ( pSuppF->nRefs++ > 0 )
+ continue;
+ if ( pSuppF->nSize == 1 )
+ continue;
+ aArea += Ivy_FastMapNodeRef( pAig, pNodeChild );
+ }
+ return aArea;
+}
+
+/**function*************************************************************
+
+ synopsis [Dereferences the cut.]
+
+ description [This procedure is similar to the procedure NodeRecusiveDeref.]
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+int Ivy_FastMapNodeDeref( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSupp, * pSuppF;
+ Ivy_Obj_t * pNodeChild;
+ int aArea, i;
+ // start the area of this cut
+ aArea = 1;
+ // go through the children
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->nSize > 1 );
+ for ( i = 0; i < pSupp->nSize; i++ )
+ {
+ pNodeChild = Ivy_ManObj(pAig, pSupp->pArray[i]);
+ pSuppF = Ivy_ObjSupp( pAig, pNodeChild );
+ assert( pSuppF->nRefs > 0 );
+ if ( --pSuppF->nRefs > 0 )
+ continue;
+ if ( pSuppF->nSize == 1 )
+ continue;
+ aArea += Ivy_FastMapNodeDeref( pAig, pNodeChild );
+ }
+ return aArea;
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+int Ivy_FastMapNodeAreaRefed( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSupp;
+ int aResult, aResult2;
+ if ( Ivy_ObjIsCi(pObj) )
+ return 0;
+ assert( Ivy_ObjIsNode(pObj) );
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->nRefs > 0 );
+ aResult = Ivy_FastMapNodeDeref( pAig, pObj );
+ aResult2 = Ivy_FastMapNodeRef( pAig, pObj );
+ assert( aResult == aResult2 );
+ return aResult;
+}
+
+/**function*************************************************************
+
+ synopsis [Computes the exact area associated with the cut.]
+
+ description []
+
+ sideeffects []
+
+ seealso []
+
+***********************************************************************/
+int Ivy_FastMapNodeAreaDerefed( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSupp;
+ int aResult, aResult2;
+ if ( Ivy_ObjIsCi(pObj) )
+ return 0;
+ assert( Ivy_ObjIsNode(pObj) );
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ assert( pSupp->nRefs == 0 );
+ aResult2 = Ivy_FastMapNodeRef( pAig, pObj );
+ aResult = Ivy_FastMapNodeDeref( pAig, pObj );
+ assert( aResult == aResult2 );
+ return aResult;
+}
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of nodes with no external fanout.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapCutCost( Ivy_Man_t * pAig, Vec_Ptr_t * vFront )
+{
+ Ivy_Supp_t * pSuppF;
+ Ivy_Obj_t * pFanin;
+ int i, Counter = 0;
+ Vec_PtrForEachEntry( vFront, pFanin, i )
+ {
+ pSuppF = Ivy_ObjSupp( pAig, pFanin );
+ if ( pSuppF->nRefs == 0 )
+ Counter++;
+ }
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs area recovery for each node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapMark_rec( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ if ( Ivy_ObjIsTravIdCurrent(pAig, pObj) )
+ return;
+ assert( Ivy_ObjIsNode(pObj) );
+ Ivy_FastMapMark_rec( pAig, Ivy_ObjFanin0(pObj) );
+ Ivy_FastMapMark_rec( pAig, Ivy_ObjFanin1(pObj) );
+ Ivy_ObjSetTravIdCurrent(pAig, pObj);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the number of fanins will grow.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeWillGrow( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pFanin0, * pFanin1;
+ assert( Ivy_ObjIsNode(pObj) );
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ return !Ivy_ObjIsTravIdCurrent(pAig, pFanin0) && !Ivy_ObjIsTravIdCurrent(pAig, pFanin1);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the increase in the number of fanins with no external refs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeFaninCost( Ivy_Man_t * pAig, Ivy_Obj_t * pObj )
+{
+ Ivy_Supp_t * pSuppF;
+ Ivy_Obj_t * pFanin;
+ int Counter = 0;
+ assert( Ivy_ObjIsNode(pObj) );
+ // check if the node has external refs
+ pSuppF = Ivy_ObjSupp( pAig, pObj );
+ if ( pSuppF->nRefs == 0 )
+ Counter--;
+ // increment the number of fanins without external refs
+ pFanin = Ivy_ObjFanin0(pObj);
+ pSuppF = Ivy_ObjSupp( pAig, pFanin );
+ if ( !Ivy_ObjIsTravIdCurrent(pAig, pFanin) && pSuppF->nRefs == 0 )
+ Counter++;
+ // increment the number of fanins without external refs
+ pFanin = Ivy_ObjFanin1(pObj);
+ pSuppF = Ivy_ObjSupp( pAig, pFanin );
+ if ( !Ivy_ObjIsTravIdCurrent(pAig, pFanin) && pSuppF->nRefs == 0 )
+ Counter++;
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the frontier.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeFaninUpdate( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Vec_Ptr_t * vFront )
+{
+ Ivy_Obj_t * pFanin;
+ assert( Ivy_ObjIsNode(pObj) );
+ Vec_PtrRemove( vFront, pObj );
+ pFanin = Ivy_ObjFanin0(pObj);
+ if ( !Ivy_ObjIsTravIdCurrent(pAig, pFanin) )
+ {
+ Ivy_ObjSetTravIdCurrent(pAig, pFanin);
+ Vec_PtrPush( vFront, pFanin );
+ }
+ pFanin = Ivy_ObjFanin1(pObj);
+ if ( !Ivy_ObjIsTravIdCurrent(pAig, pFanin) )
+ {
+ Ivy_ObjSetTravIdCurrent(pAig, pFanin);
+ Vec_PtrPush( vFront, pFanin );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compacts the number of external refs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeFaninCompact0( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront )
+{
+ Ivy_Obj_t * pFanin;
+ int i;
+ Vec_PtrForEachEntry( vFront, pFanin, i )
+ {
+ if ( Ivy_ObjIsCi(pFanin) )
+ continue;
+ if ( Ivy_FastMapNodeWillGrow(pAig, pFanin) )
+ continue;
+ if ( Ivy_FastMapNodeFaninCost(pAig, pFanin) <= 0 )
+ {
+ Ivy_FastMapNodeFaninUpdate( pAig, pFanin, vFront );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compacts the number of external refs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeFaninCompact1( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront )
+{
+ Ivy_Obj_t * pFanin;
+ int i;
+ Vec_PtrForEachEntry( vFront, pFanin, i )
+ {
+ if ( Ivy_ObjIsCi(pFanin) )
+ continue;
+ if ( Ivy_FastMapNodeFaninCost(pAig, pFanin) < 0 )
+ {
+ Ivy_FastMapNodeFaninUpdate( pAig, pFanin, vFront );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compacts the number of external refs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeFaninCompact2( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront )
+{
+ Ivy_Obj_t * pFanin;
+ int i;
+ Vec_PtrForEachEntry( vFront, pFanin, i )
+ {
+ if ( Ivy_ObjIsCi(pFanin) )
+ continue;
+ if ( Ivy_FastMapNodeFaninCost(pAig, pFanin) <= 0 )
+ {
+ Ivy_FastMapNodeFaninUpdate( pAig, pFanin, vFront );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compacts the number of external refs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FastMapNodeFaninCompact_int( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront )
+{
+ if ( Ivy_FastMapNodeFaninCompact0(pAig, pObj, nLimit, vFront) )
+ return 1;
+ if ( Vec_PtrSize(vFront) < nLimit && Ivy_FastMapNodeFaninCompact1(pAig, pObj, nLimit, vFront) )
+ return 1;
+ if ( Vec_PtrSize(vFront) < nLimit && Ivy_FastMapNodeFaninCompact2(pAig, pObj, nLimit, vFront) )
+ return 1;
+ assert( Vec_PtrSize(vFront) <= nLimit );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compacts the number of external refs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeFaninCompact( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront )
+{
+ while ( Ivy_FastMapNodeFaninCompact_int( pAig, pObj, nLimit, vFront ) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prepares node mapping.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodePrepare( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld )
+{
+ Ivy_Supp_t * pSupp;
+ Ivy_Obj_t * pFanin;
+ int i;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ // expand the cut downwards from the given place
+ Vec_PtrClear( vFront );
+ Vec_PtrClear( vFrontOld );
+ Ivy_ManIncrementTravId( pAig );
+ for ( i = 0; i < pSupp->nSize; i++ )
+ {
+ pFanin = Ivy_ManObj(pAig, pSupp->pArray[i]);
+ Vec_PtrPush( vFront, pFanin );
+ Vec_PtrPush( vFrontOld, pFanin );
+ Ivy_ObjSetTravIdCurrent( pAig, pFanin );
+ }
+ // mark the nodes in the cone
+ Ivy_FastMapMark_rec( pAig, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the frontier.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeUpdate( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, Vec_Ptr_t * vFront )
+{
+ Ivy_Supp_t * pSupp;
+ Ivy_Obj_t * pFanin;
+ int i;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ // deref node's cut
+ Ivy_FastMapNodeDeref( pAig, pObj );
+ // update the node's cut
+ pSupp->nSize = Vec_PtrSize(vFront);
+ Vec_PtrForEachEntry( vFront, pFanin, i )
+ pSupp->pArray[i] = pFanin->Id;
+ // ref the new cut
+ Ivy_FastMapNodeRef( pAig, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs area recovery for each node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeRecover2( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld )
+{
+ Ivy_Supp_t * pSupp;
+ int CostBef, CostAft;
+ int AreaBef, AreaAft;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+// if ( pSupp->nRefs == 0 )
+// return;
+ if ( pSupp->nRefs == 0 )
+ AreaBef = Ivy_FastMapNodeAreaDerefed( pAig, pObj );
+ else
+ AreaBef = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ // get the area
+ if ( AreaBef == 1 )
+ return;
+
+ if ( pSupp->nRefs == 0 )
+ {
+ pSupp->nRefs = 1000000;
+ Ivy_FastMapNodeRef( pAig, pObj );
+ }
+ // the cut is non-trivial
+ Ivy_FastMapNodePrepare( pAig, pObj, nLimit, vFront, vFrontOld );
+ // iteratively modify the cut
+ CostBef = Ivy_FastMapCutCost( pAig, vFront );
+ Ivy_FastMapNodeFaninCompact( pAig, pObj, nLimit, vFront );
+ CostAft = Ivy_FastMapCutCost( pAig, vFront );
+ assert( CostBef >= CostAft );
+ // update the node
+ Ivy_FastMapNodeUpdate( pAig, pObj, vFront );
+ // get the new area
+ AreaAft = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ if ( AreaAft > AreaBef )
+ {
+ Ivy_FastMapNodeUpdate( pAig, pObj, vFrontOld );
+ AreaAft = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ assert( AreaAft == AreaBef );
+ }
+ if ( pSupp->nRefs == 1000000 )
+ {
+ pSupp->nRefs = 0;
+ Ivy_FastMapNodeDeref( pAig, pObj );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs area recovery for each node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeRecover( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld )
+{
+ Ivy_Supp_t * pSupp;
+ int CostBef, CostAft;
+ int AreaBef, AreaAft;
+ int DelayOld;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ DelayOld = pSupp->Delay = Ivy_FastMapNodeDelay( pAig, pObj );
+ assert( pSupp->Delay <= pSupp->DelayR );
+ if ( pSupp->nRefs == 0 )
+ return;
+ // get the area
+ AreaBef = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+// if ( AreaBef == 1 )
+// return;
+ if ( pObj->Id == 102 )
+ {
+ int x = 0;
+ }
+ // the cut is non-trivial
+ Ivy_FastMapNodePrepare( pAig, pObj, nLimit, vFront, vFrontOld );
+ // iteratively modify the cut
+ Ivy_FastMapNodeDeref( pAig, pObj );
+ CostBef = Ivy_FastMapCutCost( pAig, vFront );
+ Ivy_FastMapNodeFaninCompact( pAig, pObj, nLimit, vFront );
+ CostAft = Ivy_FastMapCutCost( pAig, vFront );
+ Ivy_FastMapNodeRef( pAig, pObj );
+ assert( CostBef >= CostAft );
+ // update the node
+ Ivy_FastMapNodeUpdate( pAig, pObj, vFront );
+ pSupp->Delay = Ivy_FastMapNodeDelay( pAig, pObj );
+ // get the new area
+ AreaAft = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ if ( AreaAft > AreaBef || pSupp->Delay > pSupp->DelayR )
+ {
+ Ivy_FastMapNodeUpdate( pAig, pObj, vFrontOld );
+ AreaAft = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ assert( AreaAft == AreaBef );
+ pSupp->Delay = DelayOld;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs area recovery for each node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FastMapNodeRecover4( Ivy_Man_t * pAig, Ivy_Obj_t * pObj, int nLimit, Vec_Ptr_t * vFront, Vec_Ptr_t * vFrontOld )
+{
+ Ivy_Supp_t * pSupp;
+ int CostBef, CostAft;
+ int AreaBef, AreaAft;
+ int DelayOld;
+ pSupp = Ivy_ObjSupp( pAig, pObj );
+ DelayOld = pSupp->Delay = Ivy_FastMapNodeDelay( pAig, pObj );
+ assert( pSupp->Delay <= pSupp->DelayR );
+// if ( pSupp->nRefs == 0 )
+// return;
+// AreaBef = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ // get the area
+ if ( pSupp->nRefs == 0 )
+ AreaBef = Ivy_FastMapNodeAreaDerefed( pAig, pObj );
+ else
+ AreaBef = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ if ( AreaBef == 1 )
+ return;
+
+ if ( pSupp->nRefs == 0 )
+ {
+ pSupp->nRefs = 1000000;
+ Ivy_FastMapNodeRef( pAig, pObj );
+ }
+ // the cut is non-trivial
+ Ivy_FastMapNodePrepare( pAig, pObj, nLimit, vFront, vFrontOld );
+ // iteratively modify the cut
+ CostBef = Ivy_FastMapCutCost( pAig, vFront );
+ Ivy_FastMapNodeFaninCompact( pAig, pObj, nLimit, vFront );
+ CostAft = Ivy_FastMapCutCost( pAig, vFront );
+ assert( CostBef >= CostAft );
+ // update the node
+ Ivy_FastMapNodeUpdate( pAig, pObj, vFront );
+ pSupp->Delay = Ivy_FastMapNodeDelay( pAig, pObj );
+ // get the new area
+ AreaAft = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ if ( AreaAft > AreaBef || pSupp->Delay > pSupp->DelayR )
+ {
+ Ivy_FastMapNodeUpdate( pAig, pObj, vFrontOld );
+ AreaAft = Ivy_FastMapNodeAreaRefed( pAig, pObj );
+ assert( AreaAft == AreaBef );
+ pSupp->Delay = DelayOld;
+ }
+ if ( pSupp->nRefs == 1000000 )
+ {
+ pSupp->nRefs = 0;
+ Ivy_FastMapNodeDeref( pAig, pObj );
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyFraig.c b/src/aig/ivy/ivyFraig.c
new file mode 100644
index 00000000..4079b6ed
--- /dev/null
+++ b/src/aig/ivy/ivyFraig.c
@@ -0,0 +1,2760 @@
+/**CFile****************************************************************
+
+ FileName [ivyFraig.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Functional reduction of AIGs]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyFraig.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "satSolver.h"
+#include "extra.h"
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Ivy_FraigMan_t_ Ivy_FraigMan_t;
+typedef struct Ivy_FraigSim_t_ Ivy_FraigSim_t;
+typedef struct Ivy_FraigList_t_ Ivy_FraigList_t;
+
+struct Ivy_FraigList_t_
+{
+ Ivy_Obj_t * pHead;
+ Ivy_Obj_t * pTail;
+ int nItems;
+};
+
+struct Ivy_FraigSim_t_
+{
+ int Type;
+ Ivy_FraigSim_t * pNext;
+ Ivy_FraigSim_t * pFanin0;
+ Ivy_FraigSim_t * pFanin1;
+ unsigned pData[0];
+};
+
+struct Ivy_FraigMan_t_
+{
+ // general info
+ Ivy_FraigParams_t * pParams; // various parameters
+ // temporary backtrack limits because "sint64" cannot be defined in Ivy_FraigParams_t ...
+ sint64 nBTLimitGlobal; // global limit on the number of backtracks
+ sint64 nInsLimitGlobal;// global limit on the number of clause inspects
+ // AIG manager
+ Ivy_Man_t * pManAig; // the starting AIG manager
+ Ivy_Man_t * pManFraig; // the final AIG manager
+ // simulation information
+ int nSimWords; // the number of words
+ char * pSimWords; // the simulation info
+ Ivy_FraigSim_t * pSimStart; // the list of simulation info for internal nodes
+ // counter example storage
+ int nPatWords; // the number of words in the counter example
+ unsigned * pPatWords; // the counter example
+ int * pPatScores; // the scores of each pattern
+ // equivalence classes
+ Ivy_FraigList_t lClasses; // equivalence classes
+ Ivy_FraigList_t lCand; // candidatates
+ int nPairs; // the number of pairs of nodes
+ // equivalence checking
+ sat_solver * pSat; // SAT solver
+ int nSatVars; // the number of variables currently used
+ Vec_Ptr_t * vPiVars; // the PIs of the cone used
+ // other
+ ProgressBar * pProgress;
+ // statistics
+ int nSimRounds;
+ int nNodesMiter;
+ int nClassesZero;
+ int nClassesBeg;
+ int nClassesEnd;
+ int nPairsBeg;
+ int nPairsEnd;
+ int nSatCalls;
+ int nSatCallsSat;
+ int nSatCallsUnsat;
+ int nSatProof;
+ int nSatFails;
+ int nSatFailsReal;
+ // runtime
+ int timeSim;
+ int timeTrav;
+ int timeSat;
+ int timeSatUnsat;
+ int timeSatSat;
+ int timeSatFail;
+ int timeRef;
+ int timeTotal;
+ int time1;
+ int time2;
+};
+
+typedef struct Prove_ParamsStruct_t_ Prove_Params_t;
+struct Prove_ParamsStruct_t_
+{
+ // general parameters
+ int fUseFraiging; // enables fraiging
+ int fUseRewriting; // enables rewriting
+ int fUseBdds; // enables BDD construction when other methods fail
+ int fVerbose; // prints verbose stats
+ // iterations
+ int nItersMax; // the number of iterations
+ // mitering
+ int nMiteringLimitStart; // starting mitering limit
+ float nMiteringLimitMulti; // multiplicative coefficient to increase the limit in each iteration
+ // rewriting
+ int nRewritingLimitStart; // the number of rewriting iterations
+ float nRewritingLimitMulti; // multiplicative coefficient to increase the limit in each iteration
+ // fraiging
+ int nFraigingLimitStart; // starting backtrack(conflict) limit
+ float nFraigingLimitMulti; // multiplicative coefficient to increase the limit in each iteration
+ // last-gasp BDD construction
+ int nBddSizeLimit; // the number of BDD nodes when construction is aborted
+ int fBddReorder; // enables dynamic BDD variable reordering
+ // last-gasp mitering
+ int nMiteringLimitLast; // final mitering limit
+ // global SAT solver limits
+ sint64 nTotalBacktrackLimit; // global limit on the number of backtracks
+ sint64 nTotalInspectLimit; // global limit on the number of clause inspects
+ // global resources applied
+ sint64 nTotalBacktracksMade; // the total number of backtracks made
+ sint64 nTotalInspectsMade; // the total number of inspects made
+};
+
+static inline Ivy_FraigSim_t * Ivy_ObjSim( Ivy_Obj_t * pObj ) { return (Ivy_FraigSim_t *)pObj->pFanout; }
+static inline Ivy_Obj_t * Ivy_ObjClassNodeLast( Ivy_Obj_t * pObj ) { return pObj->pNextFan0; }
+static inline Ivy_Obj_t * Ivy_ObjClassNodeRepr( Ivy_Obj_t * pObj ) { return pObj->pNextFan0; }
+static inline Ivy_Obj_t * Ivy_ObjClassNodeNext( Ivy_Obj_t * pObj ) { return pObj->pNextFan1; }
+static inline Ivy_Obj_t * Ivy_ObjNodeHashNext( Ivy_Obj_t * pObj ) { return pObj->pPrevFan0; }
+static inline Ivy_Obj_t * Ivy_ObjEquivListNext( Ivy_Obj_t * pObj ) { return pObj->pPrevFan0; }
+static inline Ivy_Obj_t * Ivy_ObjEquivListPrev( Ivy_Obj_t * pObj ) { return pObj->pPrevFan1; }
+static inline Ivy_Obj_t * Ivy_ObjFraig( Ivy_Obj_t * pObj ) { return pObj->pEquiv; }
+static inline int Ivy_ObjSatNum( Ivy_Obj_t * pObj ) { return (int)pObj->pNextFan0; }
+static inline Vec_Ptr_t * Ivy_ObjFaninVec( Ivy_Obj_t * pObj ) { return (Vec_Ptr_t *)pObj->pNextFan1; }
+
+static inline void Ivy_ObjSetSim( Ivy_Obj_t * pObj, Ivy_FraigSim_t * pSim ) { pObj->pFanout = (Ivy_Obj_t *)pSim; }
+static inline void Ivy_ObjSetClassNodeLast( Ivy_Obj_t * pObj, Ivy_Obj_t * pLast ) { pObj->pNextFan0 = pLast; }
+static inline void Ivy_ObjSetClassNodeRepr( Ivy_Obj_t * pObj, Ivy_Obj_t * pRepr ) { pObj->pNextFan0 = pRepr; }
+static inline void Ivy_ObjSetClassNodeNext( Ivy_Obj_t * pObj, Ivy_Obj_t * pNext ) { pObj->pNextFan1 = pNext; }
+static inline void Ivy_ObjSetNodeHashNext( Ivy_Obj_t * pObj, Ivy_Obj_t * pNext ) { pObj->pPrevFan0 = pNext; }
+static inline void Ivy_ObjSetEquivListNext( Ivy_Obj_t * pObj, Ivy_Obj_t * pNext ) { pObj->pPrevFan0 = pNext; }
+static inline void Ivy_ObjSetEquivListPrev( Ivy_Obj_t * pObj, Ivy_Obj_t * pPrev ) { pObj->pPrevFan1 = pPrev; }
+static inline void Ivy_ObjSetFraig( Ivy_Obj_t * pObj, Ivy_Obj_t * pNode ) { pObj->pEquiv = pNode; }
+static inline void Ivy_ObjSetSatNum( Ivy_Obj_t * pObj, int Num ) { pObj->pNextFan0 = (Ivy_Obj_t *)Num; }
+static inline void Ivy_ObjSetFaninVec( Ivy_Obj_t * pObj, Vec_Ptr_t * vFanins ) { pObj->pNextFan1 = (Ivy_Obj_t *)vFanins; }
+
+static inline unsigned Ivy_ObjRandomSim() { return (rand() << 24) ^ (rand() << 12) ^ rand(); }
+
+// iterate through equivalence classes
+#define Ivy_FraigForEachEquivClass( pList, pEnt ) \
+ for ( pEnt = pList; \
+ pEnt; \
+ pEnt = Ivy_ObjEquivListNext(pEnt) )
+#define Ivy_FraigForEachEquivClassSafe( pList, pEnt, pEnt2 ) \
+ for ( pEnt = pList, \
+ pEnt2 = pEnt? Ivy_ObjEquivListNext(pEnt): NULL; \
+ pEnt; \
+ pEnt = pEnt2, \
+ pEnt2 = pEnt? Ivy_ObjEquivListNext(pEnt): NULL )
+// iterate through nodes in one class
+#define Ivy_FraigForEachClassNode( pClass, pEnt ) \
+ for ( pEnt = pClass; \
+ pEnt; \
+ pEnt = Ivy_ObjClassNodeNext(pEnt) )
+// iterate through nodes in the hash table
+#define Ivy_FraigForEachBinNode( pBin, pEnt ) \
+ for ( pEnt = pBin; \
+ pEnt; \
+ pEnt = Ivy_ObjNodeHashNext(pEnt) )
+
+static Ivy_FraigMan_t * Ivy_FraigStart( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams );
+static Ivy_FraigMan_t * Ivy_FraigStartSimple( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams );
+static Ivy_Man_t * Ivy_FraigPerform_int( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams, sint64 nBTLimitGlobal, sint64 nInsLimitGlobal, sint64 * pnSatConfs, sint64 * pnSatInspects );
+static void Ivy_FraigPrint( Ivy_FraigMan_t * p );
+static void Ivy_FraigStop( Ivy_FraigMan_t * p );
+static void Ivy_FraigSimulate( Ivy_FraigMan_t * p );
+static void Ivy_FraigSweep( Ivy_FraigMan_t * p );
+static Ivy_Obj_t * Ivy_FraigAnd( Ivy_FraigMan_t * p, Ivy_Obj_t * pObjOld );
+static int Ivy_FraigNodesAreEquiv( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj0, Ivy_Obj_t * pObj1 );
+static int Ivy_FraigNodeIsConst( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj );
+static void Ivy_FraigNodeAddToSolver( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj0, Ivy_Obj_t * pObj1 );
+static int Ivy_FraigSetActivityFactors( Ivy_FraigMan_t * p, Ivy_Obj_t * pOld, Ivy_Obj_t * pNew );
+static void Ivy_FraigAddToPatScores( Ivy_FraigMan_t * p, Ivy_Obj_t * pClass, Ivy_Obj_t * pClassNew );
+static int Ivy_FraigMiterStatus( Ivy_Man_t * pMan );
+static void Ivy_FraigMiterProve( Ivy_FraigMan_t * p );
+static void Ivy_FraigMiterPrint( Ivy_Man_t * pNtk, char * pString, int clk, int fVerbose );
+static int * Ivy_FraigCreateModel( Ivy_FraigMan_t * p );
+
+static int Ivy_FraigNodesAreEquivBdd( Ivy_Obj_t * pObj1, Ivy_Obj_t * pObj2 );
+
+static sint64 s_nBTLimitGlobal = 0;
+static sint64 s_nInsLimitGlobal = 0;
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Sets the default solving parameters.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigParamsDefault( Ivy_FraigParams_t * pParams )
+{
+ memset( pParams, 0, sizeof(Ivy_FraigParams_t) );
+ pParams->nSimWords = 32; // the number of words in the simulation info
+ pParams->dSimSatur = 0.005; // the ratio of refined classes when saturation is reached
+ pParams->fPatScores = 0; // enables simulation pattern scoring
+ pParams->MaxScore = 25; // max score after which resimulation is used
+ pParams->fDoSparse = 1; // skips sparse functions
+// pParams->dActConeRatio = 0.05; // the ratio of cone to be bumped
+// pParams->dActConeBumpMax = 5.0; // the largest bump of activity
+ pParams->dActConeRatio = 0.3; // the ratio of cone to be bumped
+ pParams->dActConeBumpMax = 10.0; // the largest bump of activity
+
+ pParams->nBTLimitNode = 100; // conflict limit at a node
+ pParams->nBTLimitMiter = 500000; // conflict limit at an output
+// pParams->nBTLimitGlobal = 0; // conflict limit global
+// pParams->nInsLimitGlobal = 0; // inspection limit global
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs combinational equivalence checking for the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigProve( Ivy_Man_t ** ppManAig, void * pPars )
+{
+ Prove_Params_t * pParams = pPars;
+ Ivy_FraigParams_t Params, * pIvyParams = &Params;
+ Ivy_Man_t * pManAig, * pManTemp;
+ int RetValue, nIter, clk, timeStart = clock();//, Counter;
+ sint64 nSatConfs, nSatInspects;
+
+ // start the network and parameters
+ pManAig = *ppManAig;
+ Ivy_FraigParamsDefault( pIvyParams );
+ pIvyParams->fVerbose = pParams->fVerbose;
+ pIvyParams->fProve = 1;
+
+ if ( pParams->fVerbose )
+ {
+ printf( "RESOURCE LIMITS: Iterations = %d. Rewriting = %s. Fraiging = %s.\n",
+ pParams->nItersMax, pParams->fUseRewriting? "yes":"no", pParams->fUseFraiging? "yes":"no" );
+ printf( "Miter = %d (%3.1f). Rwr = %d (%3.1f). Fraig = %d (%3.1f). Last = %d.\n",
+ pParams->nMiteringLimitStart, pParams->nMiteringLimitMulti,
+ pParams->nRewritingLimitStart, pParams->nRewritingLimitMulti,
+ pParams->nFraigingLimitStart, pParams->nFraigingLimitMulti, pParams->nMiteringLimitLast );
+ }
+
+ // if SAT only, solve without iteration
+ if ( !pParams->fUseRewriting && !pParams->fUseFraiging )
+ {
+ clk = clock();
+ pIvyParams->nBTLimitMiter = pParams->nMiteringLimitLast / Ivy_ManPoNum(pManAig);
+ pManAig = Ivy_FraigMiter( pManTemp = pManAig, pIvyParams ); Ivy_ManStop( pManTemp );
+ RetValue = Ivy_FraigMiterStatus( pManAig );
+ Ivy_FraigMiterPrint( pManAig, "SAT solving", clk, pParams->fVerbose );
+ *ppManAig = pManAig;
+ return RetValue;
+ }
+
+ if ( Ivy_ManNodeNum(pManAig) < 500 )
+ {
+ // run the first mitering
+ clk = clock();
+ pIvyParams->nBTLimitMiter = pParams->nMiteringLimitStart / Ivy_ManPoNum(pManAig);
+ pManAig = Ivy_FraigMiter( pManTemp = pManAig, pIvyParams ); Ivy_ManStop( pManTemp );
+ RetValue = Ivy_FraigMiterStatus( pManAig );
+ Ivy_FraigMiterPrint( pManAig, "SAT solving", clk, pParams->fVerbose );
+ if ( RetValue >= 0 )
+ {
+ *ppManAig = pManAig;
+ return RetValue;
+ }
+ }
+
+ // check the current resource limits
+ RetValue = -1;
+ for ( nIter = 0; nIter < pParams->nItersMax; nIter++ )
+ {
+ if ( pParams->fVerbose )
+ {
+ printf( "ITERATION %2d : Confs = %6d. FraigBTL = %3d. \n", nIter+1,
+ (int)(pParams->nMiteringLimitStart * pow(pParams->nMiteringLimitMulti,nIter)),
+ (int)(pParams->nFraigingLimitStart * pow(pParams->nFraigingLimitMulti,nIter)) );
+ fflush( stdout );
+ }
+
+ // try rewriting
+ if ( pParams->fUseRewriting )
+ { // bug in Ivy_NodeFindCutsAll() when leaves are identical!
+/*
+ clk = clock();
+ Counter = (int)(pParams->nRewritingLimitStart * pow(pParams->nRewritingLimitMulti,nIter));
+ pManAig = Ivy_ManRwsat( pManAig, 0 );
+ RetValue = Ivy_FraigMiterStatus( pManAig );
+ Ivy_FraigMiterPrint( pManAig, "Rewriting ", clk, pParams->fVerbose );
+*/
+ }
+ if ( RetValue >= 0 )
+ break;
+
+ // try fraiging followed by mitering
+ if ( pParams->fUseFraiging )
+ {
+ clk = clock();
+ pIvyParams->nBTLimitNode = (int)(pParams->nFraigingLimitStart * pow(pParams->nFraigingLimitMulti,nIter));
+ pIvyParams->nBTLimitMiter = (int)(pParams->nMiteringLimitStart * pow(pParams->nMiteringLimitMulti,nIter)) / Ivy_ManPoNum(pManAig);
+ pManAig = Ivy_FraigPerform_int( pManTemp = pManAig, pIvyParams, pParams->nTotalBacktrackLimit, pParams->nTotalInspectLimit, &nSatConfs, &nSatInspects ); Ivy_ManStop( pManTemp );
+ RetValue = Ivy_FraigMiterStatus( pManAig );
+ Ivy_FraigMiterPrint( pManAig, "Fraiging ", clk, pParams->fVerbose );
+ }
+ if ( RetValue >= 0 )
+ break;
+
+ // add to the number of backtracks and inspects
+ pParams->nTotalBacktracksMade += nSatConfs;
+ pParams->nTotalInspectsMade += nSatInspects;
+ // check if global resource limit is reached
+ if ( (pParams->nTotalBacktrackLimit && pParams->nTotalBacktracksMade >= pParams->nTotalBacktrackLimit) ||
+ (pParams->nTotalInspectLimit && pParams->nTotalInspectsMade >= pParams->nTotalInspectLimit) )
+ {
+ printf( "Reached global limit on conflicts/inspects. Quitting.\n" );
+ *ppManAig = pManAig;
+ return -1;
+ }
+ }
+
+ if ( RetValue < 0 )
+ {
+ if ( pParams->fVerbose )
+ {
+ printf( "Attempting SAT with conflict limit %d ...\n", pParams->nMiteringLimitLast );
+ fflush( stdout );
+ }
+ clk = clock();
+ pIvyParams->nBTLimitMiter = pParams->nMiteringLimitLast / Ivy_ManPoNum(pManAig);
+ if ( pParams->nTotalBacktrackLimit )
+ s_nBTLimitGlobal = pParams->nTotalBacktrackLimit - pParams->nTotalBacktracksMade;
+ if ( pParams->nTotalInspectLimit )
+ s_nInsLimitGlobal = pParams->nTotalInspectLimit - pParams->nTotalInspectsMade;
+ pManAig = Ivy_FraigMiter( pManTemp = pManAig, pIvyParams ); Ivy_ManStop( pManTemp );
+ s_nBTLimitGlobal = 0;
+ s_nInsLimitGlobal = 0;
+ RetValue = Ivy_FraigMiterStatus( pManAig );
+ Ivy_FraigMiterPrint( pManAig, "SAT solving", clk, pParams->fVerbose );
+ // make sure that the sover never returns "undecided" when infinite resource limits are set
+ if( RetValue == -1 && pParams->nTotalInspectLimit == 0 &&
+ pParams->nTotalBacktrackLimit == 0 )
+ {
+ extern void Prove_ParamsPrint( Prove_Params_t * pParams );
+ Prove_ParamsPrint( pParams );
+ printf("ERROR: ABC has returned \"undecided\" in spite of no limits...\n");
+ exit(1);
+ }
+ }
+
+ // assign the model if it was proved by rewriting (const 1 miter)
+ if ( RetValue == 0 && pManAig->pData == NULL )
+ {
+ pManAig->pData = ALLOC( int, Ivy_ManPiNum(pManAig) );
+ memset( pManAig->pData, 0, sizeof(int) * Ivy_ManPiNum(pManAig) );
+ }
+ *ppManAig = pManAig;
+ return RetValue;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fraiging of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_FraigPerform_int( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams, sint64 nBTLimitGlobal, sint64 nInsLimitGlobal, sint64 * pnSatConfs, sint64 * pnSatInspects )
+{
+ Ivy_FraigMan_t * p;
+ Ivy_Man_t * pManAigNew;
+ int clk;
+ if ( Ivy_ManNodeNum(pManAig) == 0 )
+ return Ivy_ManDup(pManAig);
+clk = clock();
+ assert( Ivy_ManLatchNum(pManAig) == 0 );
+ p = Ivy_FraigStart( pManAig, pParams );
+ // set global limits
+ p->nBTLimitGlobal = nBTLimitGlobal;
+ p->nInsLimitGlobal = nInsLimitGlobal;
+
+ Ivy_FraigSimulate( p );
+ Ivy_FraigSweep( p );
+ pManAigNew = p->pManFraig;
+p->timeTotal = clock() - clk;
+ if ( pnSatConfs )
+ *pnSatConfs = p->pSat? p->pSat->stats.conflicts : 0;
+ if ( pnSatInspects )
+ *pnSatInspects = p->pSat? p->pSat->stats.inspects : 0;
+ Ivy_FraigStop( p );
+ return pManAigNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fraiging of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_FraigPerform( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams )
+{
+ Ivy_FraigMan_t * p;
+ Ivy_Man_t * pManAigNew;
+ int clk;
+ if ( Ivy_ManNodeNum(pManAig) == 0 )
+ return Ivy_ManDup(pManAig);
+clk = clock();
+ assert( Ivy_ManLatchNum(pManAig) == 0 );
+ p = Ivy_FraigStart( pManAig, pParams );
+ Ivy_FraigSimulate( p );
+ Ivy_FraigSweep( p );
+ pManAigNew = p->pManFraig;
+p->timeTotal = clock() - clk;
+ Ivy_FraigStop( p );
+ return pManAigNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Applies brute-force SAT to the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_FraigMiter( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams )
+{
+ Ivy_FraigMan_t * p;
+ Ivy_Man_t * pManAigNew;
+ Ivy_Obj_t * pObj;
+ int i, clk;
+clk = clock();
+ assert( Ivy_ManLatchNum(pManAig) == 0 );
+ p = Ivy_FraigStartSimple( pManAig, pParams );
+ // set global limits
+ p->nBTLimitGlobal = s_nBTLimitGlobal;
+ p->nInsLimitGlobal = s_nInsLimitGlobal;
+ // duplicate internal nodes
+ Ivy_ManForEachNode( p->pManAig, pObj, i )
+ pObj->pEquiv = Ivy_And( p->pManFraig, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) );
+ // try to prove each output of the miter
+ Ivy_FraigMiterProve( p );
+ // add the POs
+ Ivy_ManForEachPo( p->pManAig, pObj, i )
+ Ivy_ObjCreatePo( p->pManFraig, Ivy_ObjChild0Equiv(pObj) );
+ // clean the new manager
+ Ivy_ManForEachObj( p->pManFraig, pObj, i )
+ {
+ if ( Ivy_ObjFaninVec(pObj) )
+ Vec_PtrFree( Ivy_ObjFaninVec(pObj) );
+ pObj->pNextFan0 = pObj->pNextFan1 = NULL;
+ }
+ // remove dangling nodes
+ Ivy_ManCleanup( p->pManFraig );
+ pManAigNew = p->pManFraig;
+p->timeTotal = clock() - clk;
+
+//printf( "Final nodes = %6d. ", Ivy_ManNodeNum(pManAigNew) );
+//PRT( "Time", p->timeTotal );
+ Ivy_FraigStop( p );
+ return pManAigNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the fraiging manager without simulation info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_FraigMan_t * Ivy_FraigStartSimple( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams )
+{
+ Ivy_FraigMan_t * p;
+ // allocat the fraiging manager
+ p = ALLOC( Ivy_FraigMan_t, 1 );
+ memset( p, 0, sizeof(Ivy_FraigMan_t) );
+ p->pParams = pParams;
+ p->pManAig = pManAig;
+ p->pManFraig = Ivy_ManStartFrom( pManAig );
+ p->vPiVars = Vec_PtrAlloc( 100 );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Starts the fraiging manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_FraigMan_t * Ivy_FraigStart( Ivy_Man_t * pManAig, Ivy_FraigParams_t * pParams )
+{
+ Ivy_FraigMan_t * p;
+ Ivy_FraigSim_t * pSims;
+ Ivy_Obj_t * pObj;
+ int i, k, EntrySize;
+ // clean the fanout representation
+ Ivy_ManForEachObj( pManAig, pObj, i )
+// pObj->pEquiv = pObj->pFanout = pObj->pNextFan0 = pObj->pNextFan1 = pObj->pPrevFan0 = pObj->pPrevFan1 = NULL;
+ assert( !pObj->pEquiv && !pObj->pFanout );
+ // allocat the fraiging manager
+ p = ALLOC( Ivy_FraigMan_t, 1 );
+ memset( p, 0, sizeof(Ivy_FraigMan_t) );
+ p->pParams = pParams;
+ p->pManAig = pManAig;
+ p->pManFraig = Ivy_ManStartFrom( pManAig );
+ // allocate simulation info
+ p->nSimWords = pParams->nSimWords;
+// p->pSimWords = ALLOC( unsigned, Ivy_ManObjNum(pManAig) * p->nSimWords );
+ EntrySize = sizeof(Ivy_FraigSim_t) + sizeof(unsigned) * p->nSimWords;
+ p->pSimWords = (char *)malloc( Ivy_ManObjNum(pManAig) * EntrySize );
+ memset( p->pSimWords, 0, EntrySize );
+ k = 0;
+ Ivy_ManForEachObj( pManAig, pObj, i )
+ {
+ pSims = (Ivy_FraigSim_t *)(p->pSimWords + EntrySize * k++);
+ pSims->pNext = NULL;
+ if ( Ivy_ObjIsNode(pObj) )
+ {
+ if ( p->pSimStart == NULL )
+ p->pSimStart = pSims;
+ else
+ ((Ivy_FraigSim_t *)(p->pSimWords + EntrySize * (k-2)))->pNext = pSims;
+ pSims->pFanin0 = Ivy_ObjSim( Ivy_ObjFanin0(pObj) );
+ pSims->pFanin1 = Ivy_ObjSim( Ivy_ObjFanin1(pObj) );
+ pSims->Type = (Ivy_ObjFaninPhase(Ivy_ObjChild0(pObj)) << 2) | (Ivy_ObjFaninPhase(Ivy_ObjChild1(pObj)) << 1) | pObj->fPhase;
+ }
+ else
+ {
+ pSims->pFanin0 = NULL;
+ pSims->pFanin1 = NULL;
+ pSims->Type = 0;
+ }
+ Ivy_ObjSetSim( pObj, pSims );
+ }
+ assert( k == Ivy_ManObjNum(pManAig) );
+ // allocate storage for sim pattern
+ p->nPatWords = Ivy_BitWordNum( Ivy_ManPiNum(pManAig) );
+ p->pPatWords = ALLOC( unsigned, p->nPatWords );
+ p->pPatScores = ALLOC( int, 32 * p->nSimWords );
+ p->vPiVars = Vec_PtrAlloc( 100 );
+ // set random number generator
+ srand( 0xABCABC );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the fraiging manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigStop( Ivy_FraigMan_t * p )
+{
+ if ( p->pParams->fVerbose )
+ Ivy_FraigPrint( p );
+ if ( p->vPiVars ) Vec_PtrFree( p->vPiVars );
+ if ( p->pSat ) sat_solver_delete( p->pSat );
+ FREE( p->pPatScores );
+ FREE( p->pPatWords );
+ FREE( p->pSimWords );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints stats for the fraiging manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigPrint( Ivy_FraigMan_t * p )
+{
+ double nMemory;
+ nMemory = (double)Ivy_ManObjNum(p->pManAig)*p->nSimWords*sizeof(unsigned)/(1<<20);
+ printf( "SimWords = %d. Rounds = %d. Mem = %0.2f Mb. ", p->nSimWords, p->nSimRounds, nMemory );
+ printf( "Classes: Beg = %d. End = %d.\n", p->nClassesBeg, p->nClassesEnd );
+// printf( "Limits: BTNode = %d. BTMiter = %d.\n", p->pParams->nBTLimitNode, p->pParams->nBTLimitMiter );
+ printf( "Proof = %d. Counter-example = %d. Fail = %d. FailReal = %d. Zero = %d.\n",
+ p->nSatProof, p->nSatCallsSat, p->nSatFails, p->nSatFailsReal, p->nClassesZero );
+ printf( "Final = %d. Miter = %d. Total = %d. Mux = %d. (Exor = %d.) SatVars = %d.\n",
+ Ivy_ManNodeNum(p->pManFraig), p->nNodesMiter, Ivy_ManNodeNum(p->pManAig), 0, 0, p->nSatVars );
+ if ( p->pSat ) Sat_SolverPrintStats( stdout, p->pSat );
+ PRT( "AIG simulation ", p->timeSim );
+ PRT( "AIG traversal ", p->timeTrav );
+ PRT( "SAT solving ", p->timeSat );
+ PRT( " Unsat ", p->timeSatUnsat );
+ PRT( " Sat ", p->timeSatSat );
+ PRT( " Fail ", p->timeSatFail );
+ PRT( "Class refining ", p->timeRef );
+ PRT( "TOTAL RUNTIME ", p->timeTotal );
+ if ( p->time1 ) { PRT( "time1 ", p->time1 ); }
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Assigns random patterns to the PI node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeAssignRandom( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_FraigSim_t * pSims;
+ int i;
+ assert( Ivy_ObjIsPi(pObj) );
+ pSims = Ivy_ObjSim(pObj);
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = Ivy_ObjRandomSim();
+}
+
+/**Function*************************************************************
+
+ Synopsis [Assigns constant patterns to the PI node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeAssignConst( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj, int fConst1 )
+{
+ Ivy_FraigSim_t * pSims;
+ int i;
+ assert( Ivy_ObjIsPi(pObj) );
+ pSims = Ivy_ObjSim(pObj);
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = fConst1? ~(unsigned)0 : 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Assings random simulation info for the PIs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigAssignRandom( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ Ivy_ManForEachPi( p->pManAig, pObj, i )
+ Ivy_NodeAssignRandom( p, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Assings distance-1 simulation info for the PIs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigAssignDist1( Ivy_FraigMan_t * p, unsigned * pPat )
+{
+ Ivy_Obj_t * pObj;
+ int i, Limit;
+ Ivy_ManForEachPi( p->pManAig, pObj, i )
+ {
+ Ivy_NodeAssignConst( p, pObj, Ivy_InfoHasBit(pPat, i) );
+// printf( "%d", Ivy_InfoHasBit(pPat, i) );
+ }
+// printf( "\n" );
+
+ Limit = IVY_MIN( Ivy_ManPiNum(p->pManAig), p->nSimWords * 32 - 1 );
+ for ( i = 0; i < Limit; i++ )
+ Ivy_InfoXorBit( Ivy_ObjSim( Ivy_ManPi(p->pManAig,i) )->pData, i+1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if simulation info is composed of all zeros.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeHasZeroSim( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_FraigSim_t * pSims;
+ int i;
+ pSims = Ivy_ObjSim(pObj);
+ for ( i = 0; i < p->nSimWords; i++ )
+ if ( pSims->pData[i] )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if simulation info is composed of all zeros.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeComplementSim( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_FraigSim_t * pSims;
+ int i;
+ pSims = Ivy_ObjSim(pObj);
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = ~pSims->pData[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if simulation infos are equal.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeCompareSims( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj0, Ivy_Obj_t * pObj1 )
+{
+ Ivy_FraigSim_t * pSims0, * pSims1;
+ int i;
+ pSims0 = Ivy_ObjSim(pObj0);
+ pSims1 = Ivy_ObjSim(pObj1);
+ for ( i = 0; i < p->nSimWords; i++ )
+ if ( pSims0->pData[i] != pSims1->pData[i] )
+ return 0;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simulates one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeSimulateSim( Ivy_FraigMan_t * p, Ivy_FraigSim_t * pSims )
+{
+ unsigned * pData, * pData0, * pData1;
+ int i;
+ pData = pSims->pData;
+ pData0 = pSims->pFanin0->pData;
+ pData1 = pSims->pFanin1->pData;
+ switch( pSims->Type )
+ {
+ case 0:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = (pData0[i] & pData1[i]);
+ break;
+ case 1:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = ~(pData0[i] & pData1[i]);
+ break;
+ case 2:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = (pData0[i] & ~pData1[i]);
+ break;
+ case 3:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = (~pData0[i] | pData1[i]);
+ break;
+ case 4:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = (~pData0[i] & pData1[i]);
+ break;
+ case 5:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = (pData0[i] | ~pData1[i]);
+ break;
+ case 6:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = ~(pData0[i] | pData1[i]);
+ break;
+ case 7:
+ for ( i = 0; i < p->nSimWords; i++ )
+ pData[i] = (pData0[i] | pData1[i]);
+ break;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simulates one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeSimulate( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_FraigSim_t * pSims, * pSims0, * pSims1;
+ int fCompl, fCompl0, fCompl1, i;
+ assert( !Ivy_IsComplement(pObj) );
+ // get hold of the simulation information
+ pSims = Ivy_ObjSim(pObj);
+ pSims0 = Ivy_ObjSim(Ivy_ObjFanin0(pObj));
+ pSims1 = Ivy_ObjSim(Ivy_ObjFanin1(pObj));
+ // get complemented attributes of the children using their random info
+ fCompl = pObj->fPhase;
+ fCompl0 = Ivy_ObjFaninPhase(Ivy_ObjChild0(pObj));
+ fCompl1 = Ivy_ObjFaninPhase(Ivy_ObjChild1(pObj));
+ // simulate
+ if ( fCompl0 && fCompl1 )
+ {
+ if ( fCompl )
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = (pSims0->pData[i] | pSims1->pData[i]);
+ else
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = ~(pSims0->pData[i] | pSims1->pData[i]);
+ }
+ else if ( fCompl0 && !fCompl1 )
+ {
+ if ( fCompl )
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = (pSims0->pData[i] | ~pSims1->pData[i]);
+ else
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = (~pSims0->pData[i] & pSims1->pData[i]);
+ }
+ else if ( !fCompl0 && fCompl1 )
+ {
+ if ( fCompl )
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = (~pSims0->pData[i] | pSims1->pData[i]);
+ else
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = (pSims0->pData[i] & ~pSims1->pData[i]);
+ }
+ else // if ( !fCompl0 && !fCompl1 )
+ {
+ if ( fCompl )
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = ~(pSims0->pData[i] & pSims1->pData[i]);
+ else
+ for ( i = 0; i < p->nSimWords; i++ )
+ pSims->pData[i] = (pSims0->pData[i] & pSims1->pData[i]);
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes hash value using simulation info.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_NodeHash( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj )
+{
+ static int s_FPrimes[128] = {
+ 1009, 1049, 1093, 1151, 1201, 1249, 1297, 1361, 1427, 1459,
+ 1499, 1559, 1607, 1657, 1709, 1759, 1823, 1877, 1933, 1997,
+ 2039, 2089, 2141, 2213, 2269, 2311, 2371, 2411, 2467, 2543,
+ 2609, 2663, 2699, 2741, 2797, 2851, 2909, 2969, 3037, 3089,
+ 3169, 3221, 3299, 3331, 3389, 3461, 3517, 3557, 3613, 3671,
+ 3719, 3779, 3847, 3907, 3943, 4013, 4073, 4129, 4201, 4243,
+ 4289, 4363, 4441, 4493, 4549, 4621, 4663, 4729, 4793, 4871,
+ 4933, 4973, 5021, 5087, 5153, 5227, 5281, 5351, 5417, 5471,
+ 5519, 5573, 5651, 5693, 5749, 5821, 5861, 5923, 6011, 6073,
+ 6131, 6199, 6257, 6301, 6353, 6397, 6481, 6563, 6619, 6689,
+ 6737, 6803, 6863, 6917, 6977, 7027, 7109, 7187, 7237, 7309,
+ 7393, 7477, 7523, 7561, 7607, 7681, 7727, 7817, 7877, 7933,
+ 8011, 8039, 8059, 8081, 8093, 8111, 8123, 8147
+ };
+ Ivy_FraigSim_t * pSims;
+ unsigned uHash;
+ int i;
+ assert( p->nSimWords <= 128 );
+ uHash = 0;
+ pSims = Ivy_ObjSim(pObj);
+ for ( i = 0; i < p->nSimWords; i++ )
+ uHash ^= pSims->pData[i] * s_FPrimes[i];
+ return uHash;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simulates AIG manager.]
+
+ Description [Assumes that the PI simulation info is attached.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSimulateOne( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i, clk;
+clk = clock();
+ Ivy_ManForEachNode( p->pManAig, pObj, i )
+ {
+ Ivy_NodeSimulate( p, pObj );
+/*
+ if ( Ivy_ObjFraig(pObj) == NULL )
+ printf( "%3d --- -- %d : ", pObj->Id, pObj->fPhase );
+ else
+ printf( "%3d %3d %2d %d : ", pObj->Id, Ivy_Regular(Ivy_ObjFraig(pObj))->Id, Ivy_ObjSatNum(Ivy_Regular(Ivy_ObjFraig(pObj))), pObj->fPhase );
+ Extra_PrintBinary( stdout, Ivy_ObjSim(pObj), 30 );
+ printf( "\n" );
+*/
+ }
+p->timeSim += clock() - clk;
+p->nSimRounds++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simulates AIG manager.]
+
+ Description [Assumes that the PI simulation info is attached.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSimulateOneSim( Ivy_FraigMan_t * p )
+{
+ Ivy_FraigSim_t * pSims;
+ int clk;
+clk = clock();
+ for ( pSims = p->pSimStart; pSims; pSims = pSims->pNext )
+ Ivy_NodeSimulateSim( p, pSims );
+p->timeSim += clock() - clk;
+p->nSimRounds++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds one node to the equivalence class.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeAddToClass( Ivy_Obj_t * pClass, Ivy_Obj_t * pObj )
+{
+ if ( Ivy_ObjClassNodeNext(pClass) == NULL )
+ Ivy_ObjSetClassNodeNext( pClass, pObj );
+ else
+ Ivy_ObjSetClassNodeNext( Ivy_ObjClassNodeLast(pClass), pObj );
+ Ivy_ObjSetClassNodeLast( pClass, pObj );
+ Ivy_ObjSetClassNodeRepr( pObj, pClass );
+ Ivy_ObjSetClassNodeNext( pObj, NULL );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds equivalence class to the list of classes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigAddClass( Ivy_FraigList_t * pList, Ivy_Obj_t * pClass )
+{
+ if ( pList->pHead == NULL )
+ {
+ pList->pHead = pClass;
+ pList->pTail = pClass;
+ Ivy_ObjSetEquivListPrev( pClass, NULL );
+ Ivy_ObjSetEquivListNext( pClass, NULL );
+ }
+ else
+ {
+ Ivy_ObjSetEquivListNext( pList->pTail, pClass );
+ Ivy_ObjSetEquivListPrev( pClass, pList->pTail );
+ Ivy_ObjSetEquivListNext( pClass, NULL );
+ pList->pTail = pClass;
+ }
+ pList->nItems++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the list of classes after base class has split.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigInsertClass( Ivy_FraigList_t * pList, Ivy_Obj_t * pBase, Ivy_Obj_t * pClass )
+{
+ Ivy_ObjSetEquivListPrev( pClass, pBase );
+ Ivy_ObjSetEquivListNext( pClass, Ivy_ObjEquivListNext(pBase) );
+ if ( Ivy_ObjEquivListNext(pBase) )
+ Ivy_ObjSetEquivListPrev( Ivy_ObjEquivListNext(pBase), pClass );
+ Ivy_ObjSetEquivListNext( pBase, pClass );
+ if ( pList->pTail == pBase )
+ pList->pTail = pClass;
+ pList->nItems++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes equivalence class from the list of classes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigRemoveClass( Ivy_FraigList_t * pList, Ivy_Obj_t * pClass )
+{
+ if ( pList->pHead == pClass )
+ pList->pHead = Ivy_ObjEquivListNext(pClass);
+ if ( pList->pTail == pClass )
+ pList->pTail = Ivy_ObjEquivListPrev(pClass);
+ if ( Ivy_ObjEquivListPrev(pClass) )
+ Ivy_ObjSetEquivListNext( Ivy_ObjEquivListPrev(pClass), Ivy_ObjEquivListNext(pClass) );
+ if ( Ivy_ObjEquivListNext(pClass) )
+ Ivy_ObjSetEquivListPrev( Ivy_ObjEquivListNext(pClass), Ivy_ObjEquivListPrev(pClass) );
+ Ivy_ObjSetEquivListNext( pClass, NULL );
+ Ivy_ObjSetEquivListPrev( pClass, NULL );
+ pClass->fMarkA = 0;
+ pList->nItems--;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of pairs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigCountPairsClasses( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pClass, * pNode;
+ int nPairs = 0, nNodes;
+ return nPairs;
+
+ Ivy_FraigForEachEquivClass( p->lClasses.pHead, pClass )
+ {
+ nNodes = 0;
+ Ivy_FraigForEachClassNode( pClass, pNode )
+ nNodes++;
+ nPairs += nNodes * (nNodes - 1) / 2;
+ }
+ return nPairs;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates initial simulation classes.]
+
+ Description [Assumes that simulation info is assigned.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigCreateClasses( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t ** pTable;
+ Ivy_Obj_t * pObj, * pConst1, * pBin, * pEntry;
+ int i, nTableSize;
+ unsigned Hash;
+ pConst1 = Ivy_ManConst1(p->pManAig);
+ // allocate the table
+ nTableSize = Ivy_ManObjNum(p->pManAig) / 2 + 13;
+ pTable = ALLOC( Ivy_Obj_t *, nTableSize );
+ memset( pTable, 0, sizeof(Ivy_Obj_t *) * nTableSize );
+ // collect nodes into the table
+ Ivy_ManForEachObj( p->pManAig, pObj, i )
+ {
+ if ( !Ivy_ObjIsPi(pObj) && !Ivy_ObjIsNode(pObj) )
+ continue;
+ Hash = Ivy_NodeHash( p, pObj );
+ if ( Hash == 0 && Ivy_NodeHasZeroSim( p, pObj ) )
+ {
+ Ivy_NodeAddToClass( pConst1, pObj );
+ continue;
+ }
+ // add the node to the table
+ pBin = pTable[Hash % nTableSize];
+ Ivy_FraigForEachBinNode( pBin, pEntry )
+ if ( Ivy_NodeCompareSims( p, pEntry, pObj ) )
+ {
+ Ivy_NodeAddToClass( pEntry, pObj );
+ break;
+ }
+ // check if the entry was added
+ if ( pEntry )
+ continue;
+ Ivy_ObjSetNodeHashNext( pObj, pBin );
+ pTable[Hash % nTableSize] = pObj;
+ }
+ // collect non-trivial classes
+ assert( p->lClasses.pHead == NULL );
+ Ivy_ManForEachObj( p->pManAig, pObj, i )
+ {
+ if ( !Ivy_ObjIsConst1(pObj) && !Ivy_ObjIsPi(pObj) && !Ivy_ObjIsNode(pObj) )
+ continue;
+ Ivy_ObjSetNodeHashNext( pObj, NULL );
+ if ( Ivy_ObjClassNodeRepr(pObj) == NULL )
+ {
+ assert( Ivy_ObjClassNodeNext(pObj) == NULL );
+ continue;
+ }
+ // recognize the head of the class
+ if ( Ivy_ObjClassNodeNext( Ivy_ObjClassNodeRepr(pObj) ) != NULL )
+ continue;
+ // clean the class representative and add it to the list
+ Ivy_ObjSetClassNodeRepr( pObj, NULL );
+ Ivy_FraigAddClass( &p->lClasses, pObj );
+ }
+ // free the table
+ free( pTable );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively refines the class after simulation.]
+
+ Description [Returns 1 if the class has changed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigRefineClass_rec( Ivy_FraigMan_t * p, Ivy_Obj_t * pClass )
+{
+ Ivy_Obj_t * pClassNew, * pListOld, * pListNew, * pNode;
+ int RetValue = 0;
+ // check if there is refinement
+ pListOld = pClass;
+ Ivy_FraigForEachClassNode( Ivy_ObjClassNodeNext(pClass), pClassNew )
+ {
+ if ( !Ivy_NodeCompareSims(p, pClass, pClassNew) )
+ {
+ if ( p->pParams->fPatScores )
+ Ivy_FraigAddToPatScores( p, pClass, pClassNew );
+ break;
+ }
+ pListOld = pClassNew;
+ }
+ if ( pClassNew == NULL )
+ return 0;
+ // set representative of the new class
+ Ivy_ObjSetClassNodeRepr( pClassNew, NULL );
+ // start the new list
+ pListNew = pClassNew;
+ // go through the remaining nodes and sort them into two groups:
+ // (1) matches of the old node; (2) non-matches of the old node
+ Ivy_FraigForEachClassNode( Ivy_ObjClassNodeNext(pClassNew), pNode )
+ if ( Ivy_NodeCompareSims( p, pClass, pNode ) )
+ {
+ Ivy_ObjSetClassNodeNext( pListOld, pNode );
+ pListOld = pNode;
+ }
+ else
+ {
+ Ivy_ObjSetClassNodeNext( pListNew, pNode );
+ Ivy_ObjSetClassNodeRepr( pNode, pClassNew );
+ pListNew = pNode;
+ }
+ // finish both lists
+ Ivy_ObjSetClassNodeNext( pListNew, NULL );
+ Ivy_ObjSetClassNodeNext( pListOld, NULL );
+ // update the list of classes
+ Ivy_FraigInsertClass( &p->lClasses, pClass, pClassNew );
+ // if the old class is trivial, remove it
+ if ( Ivy_ObjClassNodeNext(pClass) == NULL )
+ Ivy_FraigRemoveClass( &p->lClasses, pClass );
+ // if the new class is trivial, remove it; otherwise, try to refine it
+ if ( Ivy_ObjClassNodeNext(pClassNew) == NULL )
+ Ivy_FraigRemoveClass( &p->lClasses, pClassNew );
+ else
+ RetValue = Ivy_FraigRefineClass_rec( p, pClassNew );
+ return RetValue + 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates the counter-example from the successful pattern.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigCheckOutputSimsSavePattern( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_FraigSim_t * pSims;
+ int i, k, BestPat, * pModel;
+ // find the word of the pattern
+ pSims = Ivy_ObjSim(pObj);
+ for ( i = 0; i < p->nSimWords; i++ )
+ if ( pSims->pData[i] )
+ break;
+ assert( i < p->nSimWords );
+ // find the bit of the pattern
+ for ( k = 0; k < 32; k++ )
+ if ( pSims->pData[i] & (1 << k) )
+ break;
+ assert( k < 32 );
+ // determine the best pattern
+ BestPat = i * 32 + k;
+ // fill in the counter-example data
+ pModel = ALLOC( int, Ivy_ManPiNum(p->pManFraig) );
+ Ivy_ManForEachPi( p->pManAig, pObj, i )
+ {
+ pModel[i] = Ivy_InfoHasBit(Ivy_ObjSim(pObj)->pData, BestPat);
+// printf( "%d", pModel[i] );
+ }
+// printf( "\n" );
+ // set the model
+ assert( p->pManFraig->pData == NULL );
+ p->pManFraig->pData = pModel;
+ return;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the one of the output is already non-constant 0.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigCheckOutputSims( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ // make sure the reference simulation pattern does not detect the bug
+ pObj = Ivy_ManPo( p->pManAig, 0 );
+ assert( Ivy_ObjFanin0(pObj)->fPhase == (unsigned)Ivy_ObjFaninC0(pObj) ); // Ivy_ObjFaninPhase(Ivy_ObjChild0(pObj)) == 0
+ Ivy_ManForEachPo( p->pManAig, pObj, i )
+ {
+ // complement simulation info
+// if ( Ivy_ObjFanin0(pObj)->fPhase ^ Ivy_ObjFaninC0(pObj) ) // Ivy_ObjFaninPhase(Ivy_ObjChild0(pObj))
+// Ivy_NodeComplementSim( p, Ivy_ObjFanin0(pObj) );
+ // check
+ if ( !Ivy_NodeHasZeroSim( p, Ivy_ObjFanin0(pObj) ) )
+ {
+ // create the counter-example from this pattern
+ Ivy_FraigCheckOutputSimsSavePattern( p, Ivy_ObjFanin0(pObj) );
+ return 1;
+ }
+ // complement simulation info
+// if ( Ivy_ObjFanin0(pObj)->fPhase ^ Ivy_ObjFaninC0(pObj) )
+// Ivy_NodeComplementSim( p, Ivy_ObjFanin0(pObj) );
+ }
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Refines the classes after simulation.]
+
+ Description [Assumes that simulation info is assigned. Returns the
+ number of classes refined.]
+
+ SideEffects [Large equivalence class of constant 0 may cause problems.]
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigRefineClasses( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pClass, * pClass2;
+ int clk, RetValue, Counter = 0;
+ // check if some outputs already became non-constant
+ // this is a special case when computation can be stopped!!!
+ if ( p->pParams->fProve )
+ Ivy_FraigCheckOutputSims( p );
+ if ( p->pManFraig->pData )
+ return 0;
+ // refine the classed
+clk = clock();
+ Ivy_FraigForEachEquivClassSafe( p->lClasses.pHead, pClass, pClass2 )
+ {
+ if ( pClass->fMarkA )
+ continue;
+ RetValue = Ivy_FraigRefineClass_rec( p, pClass );
+ Counter += ( RetValue > 0 );
+//if ( Ivy_ObjIsConst1(pClass) )
+//printf( "%d ", RetValue );
+//if ( Ivy_ObjIsConst1(pClass) )
+// p->time1 += clock() - clk;
+ }
+p->timeRef += clock() - clk;
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Print the class.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigPrintClass( Ivy_Obj_t * pClass )
+{
+ Ivy_Obj_t * pObj;
+ printf( "Class {" );
+ Ivy_FraigForEachClassNode( pClass, pObj )
+ printf( " %d(%d)%c", pObj->Id, pObj->Level, pObj->fPhase? '+' : '-' );
+ printf( " }\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of elements in the class.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigCountClassNodes( Ivy_Obj_t * pClass )
+{
+ Ivy_Obj_t * pObj;
+ int Counter = 0;
+ Ivy_FraigForEachClassNode( pClass, pObj )
+ Counter++;
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints simulation classes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigPrintSimClasses( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pClass;
+ Ivy_FraigForEachEquivClass( p->lClasses.pHead, pClass )
+ {
+// Ivy_FraigPrintClass( pClass );
+ printf( "%d ", Ivy_FraigCountClassNodes( pClass ) );
+ }
+// printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Generated const 0 pattern.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSavePattern0( Ivy_FraigMan_t * p )
+{
+ memset( p->pPatWords, 0, sizeof(unsigned) * p->nPatWords );
+}
+
+/**Function*************************************************************
+
+ Synopsis [[Generated const 1 pattern.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSavePattern1( Ivy_FraigMan_t * p )
+{
+ memset( p->pPatWords, 0xff, sizeof(unsigned) * p->nPatWords );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Generates the counter-example satisfying the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int * Ivy_FraigCreateModel( Ivy_FraigMan_t * p )
+{
+ int * pModel;
+ Ivy_Obj_t * pObj;
+ int i;
+ pModel = ALLOC( int, Ivy_ManPiNum(p->pManFraig) );
+ Ivy_ManForEachPi( p->pManFraig, pObj, i )
+ pModel[i] = ( p->pSat->model.ptr[Ivy_ObjSatNum(pObj)] == l_True );
+ return pModel;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copy pattern from the solver into the internal storage.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSavePattern( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ memset( p->pPatWords, 0, sizeof(unsigned) * p->nPatWords );
+ Ivy_ManForEachPi( p->pManFraig, pObj, i )
+// Vec_PtrForEachEntry( p->vPiVars, pObj, i )
+ if ( p->pSat->model.ptr[Ivy_ObjSatNum(pObj)] == l_True )
+ Ivy_InfoSetBit( p->pPatWords, i );
+// Ivy_InfoSetBit( p->pPatWords, pObj->Id - 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copy pattern from the solver into the internal storage.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSavePattern2( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ memset( p->pPatWords, 0, sizeof(unsigned) * p->nPatWords );
+// Ivy_ManForEachPi( p->pManFraig, pObj, i )
+ Vec_PtrForEachEntry( p->vPiVars, pObj, i )
+ if ( p->pSat->model.ptr[Ivy_ObjSatNum(pObj)] == l_True )
+// Ivy_InfoSetBit( p->pPatWords, i );
+ Ivy_InfoSetBit( p->pPatWords, pObj->Id - 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Copy pattern from the solver into the internal storage.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSavePattern3( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ for ( i = 0; i < p->nPatWords; i++ )
+ p->pPatWords[i] = Ivy_ObjRandomSim();
+ Vec_PtrForEachEntry( p->vPiVars, pObj, i )
+ if ( Ivy_InfoHasBit( p->pPatWords, pObj->Id - 1 ) ^ (p->pSat->model.ptr[Ivy_ObjSatNum(pObj)] == l_True) )
+ Ivy_InfoXorBit( p->pPatWords, pObj->Id - 1 );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Performs simulation of the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSimulate( Ivy_FraigMan_t * p )
+{
+ int nChanges, nClasses;
+ // start the classes
+ Ivy_FraigAssignRandom( p );
+ Ivy_FraigSimulateOne( p );
+ Ivy_FraigCreateClasses( p );
+//printf( "Starting classes = %5d. Pairs = %6d.\n", p->lClasses.nItems, Ivy_FraigCountPairsClasses(p) );
+ // refine classes by walking 0/1 patterns
+ Ivy_FraigSavePattern0( p );
+ Ivy_FraigAssignDist1( p, p->pPatWords );
+ Ivy_FraigSimulateOne( p );
+ nChanges = Ivy_FraigRefineClasses( p );
+ if ( p->pManFraig->pData )
+ return;
+//printf( "Refined classes = %5d. Changes = %4d. Pairs = %6d.\n", p->lClasses.nItems, nChanges, Ivy_FraigCountPairsClasses(p) );
+ Ivy_FraigSavePattern1( p );
+ Ivy_FraigAssignDist1( p, p->pPatWords );
+ Ivy_FraigSimulateOne( p );
+ nChanges = Ivy_FraigRefineClasses( p );
+ if ( p->pManFraig->pData )
+ return;
+//printf( "Refined classes = %5d. Changes = %4d. Pairs = %6d.\n", p->lClasses.nItems, nChanges, Ivy_FraigCountPairsClasses(p) );
+ // refine classes by random simulation
+ do {
+ Ivy_FraigAssignRandom( p );
+ Ivy_FraigSimulateOne( p );
+ nClasses = p->lClasses.nItems;
+ nChanges = Ivy_FraigRefineClasses( p );
+ if ( p->pManFraig->pData )
+ return;
+//printf( "Refined classes = %5d. Changes = %4d. Pairs = %6d.\n", p->lClasses.nItems, nChanges, Ivy_FraigCountPairsClasses(p) );
+ } while ( (double)nChanges / nClasses > p->pParams->dSimSatur );
+// Ivy_FraigPrintSimClasses( p );
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Cleans pattern scores.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigCleanPatScores( Ivy_FraigMan_t * p )
+{
+ int i, nLimit = p->nSimWords * 32;
+ for ( i = 0; i < nLimit; i++ )
+ p->pPatScores[i] = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds to pattern scores.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigAddToPatScores( Ivy_FraigMan_t * p, Ivy_Obj_t * pClass, Ivy_Obj_t * pClassNew )
+{
+ Ivy_FraigSim_t * pSims0, * pSims1;
+ unsigned uDiff;
+ int i, w;
+ // get hold of the simulation information
+ pSims0 = Ivy_ObjSim(pClass);
+ pSims1 = Ivy_ObjSim(pClassNew);
+ // iterate through the differences and record the score
+ for ( w = 0; w < p->nSimWords; w++ )
+ {
+ uDiff = pSims0->pData[w] ^ pSims1->pData[w];
+ if ( uDiff == 0 )
+ continue;
+ for ( i = 0; i < 32; i++ )
+ if ( uDiff & ( 1 << i ) )
+ p->pPatScores[w*32+i]++;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Selects the best pattern.]
+
+ Description [Returns 1 if such pattern is found.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigSelectBestPat( Ivy_FraigMan_t * p )
+{
+ Ivy_FraigSim_t * pSims;
+ Ivy_Obj_t * pObj;
+ int i, nLimit = p->nSimWords * 32, MaxScore = 0, BestPat = -1;
+ for ( i = 1; i < nLimit; i++ )
+ {
+ if ( MaxScore < p->pPatScores[i] )
+ {
+ MaxScore = p->pPatScores[i];
+ BestPat = i;
+ }
+ }
+ if ( MaxScore == 0 )
+ return 0;
+// if ( MaxScore > p->pParams->MaxScore )
+// printf( "Max score is %3d. ", MaxScore );
+ // copy the best pattern into the selected pattern
+ memset( p->pPatWords, 0, sizeof(unsigned) * p->nPatWords );
+ Ivy_ManForEachPi( p->pManAig, pObj, i )
+ {
+ pSims = Ivy_ObjSim(pObj);
+ if ( Ivy_InfoHasBit(pSims->pData, BestPat) )
+ Ivy_InfoSetBit(p->pPatWords, i);
+ }
+ return MaxScore;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resimulates fraiging manager after finding a counter-example.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigResimulate( Ivy_FraigMan_t * p )
+{
+ int nChanges;
+ Ivy_FraigAssignDist1( p, p->pPatWords );
+ Ivy_FraigSimulateOne( p );
+ if ( p->pParams->fPatScores )
+ Ivy_FraigCleanPatScores( p );
+ nChanges = Ivy_FraigRefineClasses( p );
+ if ( p->pManFraig->pData )
+ return;
+ if ( nChanges < 1 )
+ printf( "Error: A counter-example did not refine classes!\n" );
+ assert( nChanges >= 1 );
+//printf( "Refined classes! = %5d. Changes = %4d.\n", p->lClasses.nItems, nChanges );
+ if ( !p->pParams->fPatScores )
+ return;
+
+ // perform additional simulation using dist1 patterns derived from successful patterns
+ while ( Ivy_FraigSelectBestPat(p) > p->pParams->MaxScore )
+ {
+ Ivy_FraigAssignDist1( p, p->pPatWords );
+ Ivy_FraigSimulateOne( p );
+ Ivy_FraigCleanPatScores( p );
+ nChanges = Ivy_FraigRefineClasses( p );
+ if ( p->pManFraig->pData )
+ return;
+//printf( "Refined class!!! = %5d. Changes = %4d. Pairs = %6d.\n", p->lClasses.nItems, nChanges, Ivy_FraigCountPairsClasses(p) );
+ if ( nChanges == 0 )
+ break;
+ }
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Prints the status of the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigMiterPrint( Ivy_Man_t * pNtk, char * pString, int clk, int fVerbose )
+{
+ if ( !fVerbose )
+ return;
+ printf( "Nodes = %7d. Levels = %4d. ", Ivy_ManNodeNum(pNtk), Ivy_ManLevels(pNtk) );
+ PRT( pString, clock() - clk );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Reports the status of the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigMiterStatus( Ivy_Man_t * pMan )
+{
+ Ivy_Obj_t * pObj, * pObjNew;
+ int i, CountConst0 = 0, CountNonConst0 = 0, CountUndecided = 0;
+ if ( pMan->pData )
+ return 0;
+ Ivy_ManForEachPo( pMan, pObj, i )
+ {
+ pObjNew = Ivy_ObjChild0(pObj);
+ // check if the output is constant 1
+ if ( pObjNew == pMan->pConst1 )
+ {
+ CountNonConst0++;
+ continue;
+ }
+ // check if the output is constant 0
+ if ( pObjNew == Ivy_Not(pMan->pConst1) )
+ {
+ CountConst0++;
+ continue;
+ }
+ // check if the output can be constant 0
+ if ( Ivy_Regular(pObjNew)->fPhase != (unsigned)Ivy_IsComplement(pObjNew) )
+ {
+ CountNonConst0++;
+ continue;
+ }
+ CountUndecided++;
+ }
+/*
+ if ( p->pParams->fVerbose )
+ {
+ printf( "Miter has %d outputs. ", Ivy_ManPoNum(p->pManAig) );
+ printf( "Const0 = %d. ", CountConst0 );
+ printf( "NonConst0 = %d. ", CountNonConst0 );
+ printf( "Undecided = %d. ", CountUndecided );
+ printf( "\n" );
+ }
+*/
+ if ( CountNonConst0 )
+ return 0;
+ if ( CountUndecided )
+ return -1;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Tries to prove each output of the miter until encountering a sat output.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigMiterProve( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj, * pObjNew;
+ int i, RetValue, clk = clock();
+ int fVerbose = 0;
+ Ivy_ManForEachPo( p->pManAig, pObj, i )
+ {
+ if ( i && fVerbose )
+ {
+ PRT( "Time", clock() -clk );
+ }
+ pObjNew = Ivy_ObjChild0Equiv(pObj);
+ // check if the output is constant 1
+ if ( pObjNew == p->pManFraig->pConst1 )
+ {
+ if ( fVerbose )
+ printf( "Output %2d (out of %2d) is constant 1. ", i, Ivy_ManPoNum(p->pManAig) );
+ // assing constant 0 model
+ p->pManFraig->pData = ALLOC( int, Ivy_ManPiNum(p->pManFraig) );
+ memset( p->pManFraig->pData, 0, sizeof(int) * Ivy_ManPiNum(p->pManFraig) );
+ break;
+ }
+ // check if the output is constant 0
+ if ( pObjNew == Ivy_Not(p->pManFraig->pConst1) )
+ {
+ if ( fVerbose )
+ printf( "Output %2d (out of %2d) is already constant 0. ", i, Ivy_ManPoNum(p->pManAig) );
+ continue;
+ }
+ // check if the output can be constant 0
+ if ( Ivy_Regular(pObjNew)->fPhase != (unsigned)Ivy_IsComplement(pObjNew) )
+ {
+ if ( fVerbose )
+ printf( "Output %2d (out of %2d) cannot be constant 0. ", i, Ivy_ManPoNum(p->pManAig) );
+ // assing constant 0 model
+ p->pManFraig->pData = ALLOC( int, Ivy_ManPiNum(p->pManFraig) );
+ memset( p->pManFraig->pData, 0, sizeof(int) * Ivy_ManPiNum(p->pManFraig) );
+ break;
+ }
+/*
+ // check the representative of this node
+ pRepr = Ivy_ObjClassNodeRepr(Ivy_ObjFanin0(pObj));
+ if ( Ivy_Regular(pRepr) != p->pManAig->pConst1 )
+ printf( "Representative is not constant 1.\n" );
+ else
+ printf( "Representative is constant 1.\n" );
+*/
+ // try to prove the output constant 0
+ RetValue = Ivy_FraigNodeIsConst( p, Ivy_Regular(pObjNew) );
+ if ( RetValue == 1 ) // proved equivalent
+ {
+ if ( fVerbose )
+ printf( "Output %2d (out of %2d) was proved constant 0. ", i, Ivy_ManPoNum(p->pManAig) );
+ // set the constant miter
+ Ivy_ObjFanin0(pObj)->pEquiv = Ivy_NotCond( p->pManFraig->pConst1, !Ivy_ObjFaninC0(pObj) );
+ continue;
+ }
+ if ( RetValue == -1 ) // failed
+ {
+ if ( fVerbose )
+ printf( "Output %2d (out of %2d) has timed out at %d backtracks. ", i, Ivy_ManPoNum(p->pManAig), p->pParams->nBTLimitMiter );
+ continue;
+ }
+ // proved satisfiable
+ if ( fVerbose )
+ printf( "Output %2d (out of %2d) was proved NOT a constant 0. ", i, Ivy_ManPoNum(p->pManAig) );
+ // create the model
+ p->pManFraig->pData = Ivy_FraigCreateModel(p);
+ break;
+ }
+ if ( fVerbose )
+ {
+ PRT( "Time", clock() -clk );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fraiging for the internal nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigSweep( Ivy_FraigMan_t * p )
+{
+ Ivy_Obj_t * pObj;//, * pTemp;
+ int i, k = 0;
+p->nClassesZero = p->lClasses.pHead? (Ivy_ObjIsConst1(p->lClasses.pHead) ? Ivy_FraigCountClassNodes(p->lClasses.pHead) : 0) : 0;
+p->nClassesBeg = p->lClasses.nItems;
+ // duplicate internal nodes
+ p->pProgress = Extra_ProgressBarStart( stdout, Ivy_ManNodeNum(p->pManAig) );
+ Ivy_ManForEachNode( p->pManAig, pObj, i )
+ {
+ Extra_ProgressBarUpdate( p->pProgress, k++, NULL );
+ // default to simple strashing if simulation detected a counter-example for a PO
+ if ( p->pManFraig->pData )
+ pObj->pEquiv = Ivy_And( p->pManFraig, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) );
+ else
+ pObj->pEquiv = Ivy_FraigAnd( p, pObj );
+ assert( pObj->pEquiv != NULL );
+// pTemp = Ivy_Regular(pObj->pEquiv);
+// assert( Ivy_Regular(pObj->pEquiv)->Type );
+ }
+ Extra_ProgressBarStop( p->pProgress );
+p->nClassesEnd = p->lClasses.nItems;
+ // try to prove the outputs of the miter
+ p->nNodesMiter = Ivy_ManNodeNum(p->pManFraig);
+// Ivy_FraigMiterStatus( p->pManFraig );
+ if ( p->pParams->fProve && p->pManFraig->pData == NULL )
+ Ivy_FraigMiterProve( p );
+ // add the POs
+ Ivy_ManForEachPo( p->pManAig, pObj, i )
+ Ivy_ObjCreatePo( p->pManFraig, Ivy_ObjChild0Equiv(pObj) );
+ // clean the old manager
+ Ivy_ManForEachObj( p->pManAig, pObj, i )
+ pObj->pFanout = pObj->pNextFan0 = pObj->pNextFan1 = pObj->pPrevFan0 = pObj->pPrevFan1 = NULL;
+ // clean the new manager
+ Ivy_ManForEachObj( p->pManFraig, pObj, i )
+ {
+ if ( Ivy_ObjFaninVec(pObj) )
+ Vec_PtrFree( Ivy_ObjFaninVec(pObj) );
+ pObj->pNextFan0 = pObj->pNextFan1 = NULL;
+ }
+ // remove dangling nodes
+ Ivy_ManCleanup( p->pManFraig );
+ // clean up the class marks
+ Ivy_FraigForEachEquivClass( p->lClasses.pHead, pObj )
+ pObj->fMarkA = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs fraiging for one node.]
+
+ Description [Returns the fraiged node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_FraigAnd( Ivy_FraigMan_t * p, Ivy_Obj_t * pObjOld )
+{
+ Ivy_Obj_t * pObjNew, * pFanin0New, * pFanin1New, * pObjReprNew;
+ int RetValue;
+ // get the fraiged fanins
+ pFanin0New = Ivy_ObjChild0Equiv(pObjOld);
+ pFanin1New = Ivy_ObjChild1Equiv(pObjOld);
+ // get the candidate fraig node
+ pObjNew = Ivy_And( p->pManFraig, pFanin0New, pFanin1New );
+ // get representative of this class
+ if ( Ivy_ObjClassNodeRepr(pObjOld) == NULL || // this is a unique node
+ (!p->pParams->fDoSparse && Ivy_ObjClassNodeRepr(pObjOld) == p->pManAig->pConst1) ) // this is a sparse node
+ {
+ assert( Ivy_Regular(pFanin0New) != Ivy_Regular(pFanin1New) );
+ assert( pObjNew != Ivy_Regular(pFanin0New) );
+ assert( pObjNew != Ivy_Regular(pFanin1New) );
+ return pObjNew;
+ }
+ // get the fraiged representative
+ pObjReprNew = Ivy_ObjFraig(Ivy_ObjClassNodeRepr(pObjOld));
+ // if the fraiged nodes are the same return
+ if ( Ivy_Regular(pObjNew) == Ivy_Regular(pObjReprNew) )
+ return pObjNew;
+ assert( Ivy_Regular(pObjNew) != Ivy_ManConst1(p->pManFraig) );
+// printf( "Node = %d. Repr = %d.\n", pObjOld->Id, Ivy_ObjClassNodeRepr(pObjOld)->Id );
+
+ // they are different (the counter-example is in p->pPatWords)
+ RetValue = Ivy_FraigNodesAreEquiv( p, Ivy_Regular(pObjReprNew), Ivy_Regular(pObjNew) );
+ if ( RetValue == 1 ) // proved equivalent
+ {
+ // mark the class as proved
+ if ( Ivy_ObjClassNodeNext(pObjOld) == NULL )
+ Ivy_ObjClassNodeRepr(pObjOld)->fMarkA = 1;
+ return Ivy_NotCond( pObjReprNew, pObjOld->fPhase ^ Ivy_ObjClassNodeRepr(pObjOld)->fPhase );
+ }
+ if ( RetValue == -1 ) // failed
+ return pObjNew;
+ // simulate the counter-example and return the new node
+ Ivy_FraigResimulate( p );
+ return pObjNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints variable activity.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigPrintActivity( Ivy_FraigMan_t * p )
+{
+ int i;
+ for ( i = 0; i < p->nSatVars; i++ )
+ printf( "%d %.3f ", i, p->pSat->activity[i] );
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Runs equivalence test for the two nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigNodesAreEquiv( Ivy_FraigMan_t * p, Ivy_Obj_t * pOld, Ivy_Obj_t * pNew )
+{
+ int pLits[4], RetValue, RetValue1, nBTLimit, clk, clk2 = clock();
+
+ // make sure the nodes are not complemented
+ assert( !Ivy_IsComplement(pNew) );
+ assert( !Ivy_IsComplement(pOld) );
+ assert( pNew != pOld );
+
+ // if at least one of the nodes is a failed node, perform adjustments:
+ // if the backtrack limit is small, simply skip this node
+ // if the backtrack limit is > 10, take the quare root of the limit
+ nBTLimit = p->pParams->nBTLimitNode;
+ if ( nBTLimit > 0 && (pOld->fFailTfo || pNew->fFailTfo) )
+ {
+ p->nSatFails++;
+ // fail immediately
+// return -1;
+ if ( nBTLimit <= 10 )
+ return -1;
+ nBTLimit = (int)pow(nBTLimit, 0.7);
+ }
+ p->nSatCalls++;
+
+ // make sure the solver is allocated and has enough variables
+ if ( p->pSat == NULL )
+ {
+ p->pSat = sat_solver_new();
+ p->nSatVars = 1;
+ sat_solver_setnvars( p->pSat, 1000 );
+ // var 0 is reserved for const1 node - add the clause
+// pLits[0] = toLit( 0 );
+// sat_solver_addclause( p->pSat, pLits, pLits + 1 );
+ }
+
+ // if the nodes do not have SAT variables, allocate them
+ Ivy_FraigNodeAddToSolver( p, pOld, pNew );
+
+ // prepare variable activity
+ Ivy_FraigSetActivityFactors( p, pOld, pNew );
+
+ // solve under assumptions
+ // A = 1; B = 0 OR A = 1; B = 1
+clk = clock();
+ pLits[0] = toLitCond( Ivy_ObjSatNum(pOld), 0 );
+ pLits[1] = toLitCond( Ivy_ObjSatNum(pNew), pOld->fPhase == pNew->fPhase );
+//Sat_SolverWriteDimacs( p->pSat, "temp.cnf", pLits, pLits + 2, 1 );
+ RetValue1 = sat_solver_solve( p->pSat, pLits, pLits + 2,
+ (sint64)nBTLimit, (sint64)0,
+ p->nBTLimitGlobal, p->nInsLimitGlobal );
+p->timeSat += clock() - clk;
+ if ( RetValue1 == l_False )
+ {
+p->timeSatUnsat += clock() - clk;
+ pLits[0] = lit_neg( pLits[0] );
+ pLits[1] = lit_neg( pLits[1] );
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 2 );
+ assert( RetValue );
+ // continue solving the other implication
+ p->nSatCallsUnsat++;
+ }
+ else if ( RetValue1 == l_True )
+ {
+p->timeSatSat += clock() - clk;
+ Ivy_FraigSavePattern( p );
+ p->nSatCallsSat++;
+ return 0;
+ }
+ else // if ( RetValue1 == l_Undef )
+ {
+p->timeSatFail += clock() - clk;
+ // mark the node as the failed node
+ if ( pOld != p->pManFraig->pConst1 )
+ pOld->fFailTfo = 1;
+ pNew->fFailTfo = 1;
+ p->nSatFailsReal++;
+ return -1;
+ }
+
+ // if the old node was constant 0, we already know the answer
+ if ( pOld == p->pManFraig->pConst1 )
+ {
+ p->nSatProof++;
+ return 1;
+ }
+
+ // solve under assumptions
+ // A = 0; B = 1 OR A = 0; B = 0
+clk = clock();
+ pLits[0] = toLitCond( Ivy_ObjSatNum(pOld), 1 );
+ pLits[1] = toLitCond( Ivy_ObjSatNum(pNew), pOld->fPhase ^ pNew->fPhase );
+ RetValue1 = sat_solver_solve( p->pSat, pLits, pLits + 2,
+ (sint64)nBTLimit, (sint64)0,
+ p->nBTLimitGlobal, p->nInsLimitGlobal );
+p->timeSat += clock() - clk;
+ if ( RetValue1 == l_False )
+ {
+p->timeSatUnsat += clock() - clk;
+ pLits[0] = lit_neg( pLits[0] );
+ pLits[1] = lit_neg( pLits[1] );
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 2 );
+ assert( RetValue );
+ p->nSatCallsUnsat++;
+ }
+ else if ( RetValue1 == l_True )
+ {
+p->timeSatSat += clock() - clk;
+ Ivy_FraigSavePattern( p );
+ p->nSatCallsSat++;
+ return 0;
+ }
+ else // if ( RetValue1 == l_Undef )
+ {
+p->timeSatFail += clock() - clk;
+ // mark the node as the failed node
+ pOld->fFailTfo = 1;
+ pNew->fFailTfo = 1;
+ p->nSatFailsReal++;
+ return -1;
+ }
+/*
+ // check BDD proof
+ {
+ int RetVal;
+ PRT( "Sat", clock() - clk2 );
+ clk2 = clock();
+ RetVal = Ivy_FraigNodesAreEquivBdd( pOld, pNew );
+// printf( "%d ", RetVal );
+ assert( RetVal );
+ PRT( "Bdd", clock() - clk2 );
+ printf( "\n" );
+ }
+*/
+ // return SAT proof
+ p->nSatProof++;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Runs equivalence test for one node.]
+
+ Description [Returns the fraiged node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigNodeIsConst( Ivy_FraigMan_t * p, Ivy_Obj_t * pNew )
+{
+ int pLits[2], RetValue1, RetValue, clk;
+
+ // make sure the nodes are not complemented
+ assert( !Ivy_IsComplement(pNew) );
+ assert( pNew != p->pManFraig->pConst1 );
+ p->nSatCalls++;
+
+ // make sure the solver is allocated and has enough variables
+ if ( p->pSat == NULL )
+ {
+ p->pSat = sat_solver_new();
+ p->nSatVars = 1;
+ sat_solver_setnvars( p->pSat, 1000 );
+ // var 0 is reserved for const1 node - add the clause
+// pLits[0] = toLit( 0 );
+// sat_solver_addclause( p->pSat, pLits, pLits + 1 );
+ }
+
+ // if the nodes do not have SAT variables, allocate them
+ Ivy_FraigNodeAddToSolver( p, NULL, pNew );
+
+ // prepare variable activity
+ Ivy_FraigSetActivityFactors( p, NULL, pNew );
+
+ // solve under assumptions
+clk = clock();
+ pLits[0] = toLitCond( Ivy_ObjSatNum(pNew), pNew->fPhase );
+ RetValue1 = sat_solver_solve( p->pSat, pLits, pLits + 1,
+ (sint64)p->pParams->nBTLimitMiter, (sint64)0,
+ p->nBTLimitGlobal, p->nInsLimitGlobal );
+p->timeSat += clock() - clk;
+ if ( RetValue1 == l_False )
+ {
+p->timeSatUnsat += clock() - clk;
+ pLits[0] = lit_neg( pLits[0] );
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 1 );
+ assert( RetValue );
+ // continue solving the other implication
+ p->nSatCallsUnsat++;
+ }
+ else if ( RetValue1 == l_True )
+ {
+p->timeSatSat += clock() - clk;
+ if ( p->pPatWords )
+ Ivy_FraigSavePattern( p );
+ p->nSatCallsSat++;
+ return 0;
+ }
+ else // if ( RetValue1 == l_Undef )
+ {
+p->timeSatFail += clock() - clk;
+ // mark the node as the failed node
+ pNew->fFailTfo = 1;
+ p->nSatFailsReal++;
+ return -1;
+ }
+
+ // return SAT proof
+ p->nSatProof++;
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Addes clauses to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigAddClausesMux( Ivy_FraigMan_t * p, Ivy_Obj_t * pNode )
+{
+ Ivy_Obj_t * pNodeI, * pNodeT, * pNodeE;
+ int pLits[4], RetValue, VarF, VarI, VarT, VarE, fCompT, fCompE;
+
+ assert( !Ivy_IsComplement( pNode ) );
+ assert( Ivy_ObjIsMuxType( pNode ) );
+ // get nodes (I = if, T = then, E = else)
+ pNodeI = Ivy_ObjRecognizeMux( pNode, &pNodeT, &pNodeE );
+ // get the variable numbers
+ VarF = Ivy_ObjSatNum(pNode);
+ VarI = Ivy_ObjSatNum(pNodeI);
+ VarT = Ivy_ObjSatNum(Ivy_Regular(pNodeT));
+ VarE = Ivy_ObjSatNum(Ivy_Regular(pNodeE));
+ // get the complementation flags
+ fCompT = Ivy_IsComplement(pNodeT);
+ fCompE = Ivy_IsComplement(pNodeE);
+
+ // f = ITE(i, t, e)
+
+ // i' + t' + f
+ // i' + t + f'
+ // i + e' + f
+ // i + e + f'
+
+ // create four clauses
+ pLits[0] = toLitCond(VarI, 1);
+ pLits[1] = toLitCond(VarT, 1^fCompT);
+ pLits[2] = toLitCond(VarF, 0);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
+ assert( RetValue );
+ pLits[0] = toLitCond(VarI, 1);
+ pLits[1] = toLitCond(VarT, 0^fCompT);
+ pLits[2] = toLitCond(VarF, 1);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
+ assert( RetValue );
+ pLits[0] = toLitCond(VarI, 0);
+ pLits[1] = toLitCond(VarE, 1^fCompE);
+ pLits[2] = toLitCond(VarF, 0);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
+ assert( RetValue );
+ pLits[0] = toLitCond(VarI, 0);
+ pLits[1] = toLitCond(VarE, 0^fCompE);
+ pLits[2] = toLitCond(VarF, 1);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
+ assert( RetValue );
+
+ // two additional clauses
+ // t' & e' -> f'
+ // t & e -> f
+
+ // t + e + f'
+ // t' + e' + f
+
+ if ( VarT == VarE )
+ {
+// assert( fCompT == !fCompE );
+ return;
+ }
+
+ pLits[0] = toLitCond(VarT, 0^fCompT);
+ pLits[1] = toLitCond(VarE, 0^fCompE);
+ pLits[2] = toLitCond(VarF, 1);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
+ assert( RetValue );
+ pLits[0] = toLitCond(VarT, 1^fCompT);
+ pLits[1] = toLitCond(VarE, 1^fCompE);
+ pLits[2] = toLitCond(VarF, 0);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
+ assert( RetValue );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Addes clauses to the solver.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigAddClausesSuper( Ivy_FraigMan_t * p, Ivy_Obj_t * pNode, Vec_Ptr_t * vSuper )
+{
+ Ivy_Obj_t * pFanin;
+ int * pLits, nLits, RetValue, i;
+ assert( !Ivy_IsComplement(pNode) );
+ assert( Ivy_ObjIsNode( pNode ) );
+ // create storage for literals
+ nLits = Vec_PtrSize(vSuper) + 1;
+ pLits = ALLOC( int, nLits );
+ // suppose AND-gate is A & B = C
+ // add !A => !C or A + !C
+ Vec_PtrForEachEntry( vSuper, pFanin, i )
+ {
+ pLits[0] = toLitCond(Ivy_ObjSatNum(Ivy_Regular(pFanin)), Ivy_IsComplement(pFanin));
+ pLits[1] = toLitCond(Ivy_ObjSatNum(pNode), 1);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 2 );
+ assert( RetValue );
+ }
+ // add A & B => C or !A + !B + C
+ Vec_PtrForEachEntry( vSuper, pFanin, i )
+ pLits[i] = toLitCond(Ivy_ObjSatNum(Ivy_Regular(pFanin)), !Ivy_IsComplement(pFanin));
+ pLits[nLits-1] = toLitCond(Ivy_ObjSatNum(pNode), 0);
+ RetValue = sat_solver_addclause( p->pSat, pLits, pLits + nLits );
+ assert( RetValue );
+ free( pLits );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigCollectSuper_rec( Ivy_Obj_t * pObj, Vec_Ptr_t * vSuper, int fFirst, int fUseMuxes )
+{
+ // if the new node is complemented or a PI, another gate begins
+ if ( Ivy_IsComplement(pObj) || Ivy_ObjIsPi(pObj) || (!fFirst && Ivy_ObjRefs(pObj) > 1) ||
+ (fUseMuxes && Ivy_ObjIsMuxType(pObj)) )
+ {
+ Vec_PtrPushUnique( vSuper, pObj );
+ return;
+ }
+ // go through the branches
+ Ivy_FraigCollectSuper_rec( Ivy_ObjChild0(pObj), vSuper, 0, fUseMuxes );
+ Ivy_FraigCollectSuper_rec( Ivy_ObjChild1(pObj), vSuper, 0, fUseMuxes );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collects the supergate.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Ptr_t * Ivy_FraigCollectSuper( Ivy_Obj_t * pObj, int fUseMuxes )
+{
+ Vec_Ptr_t * vSuper;
+ assert( !Ivy_IsComplement(pObj) );
+ assert( !Ivy_ObjIsPi(pObj) );
+ vSuper = Vec_PtrAlloc( 4 );
+ Ivy_FraigCollectSuper_rec( pObj, vSuper, 1, fUseMuxes );
+ return vSuper;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the solver clause database.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigObjAddToFrontier( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj, Vec_Ptr_t * vFrontier )
+{
+ assert( !Ivy_IsComplement(pObj) );
+ if ( Ivy_ObjSatNum(pObj) )
+ return;
+ assert( Ivy_ObjSatNum(pObj) == 0 );
+ assert( Ivy_ObjFaninVec(pObj) == NULL );
+ if ( Ivy_ObjIsConst1(pObj) )
+ return;
+//printf( "Assigning node %d number %d\n", pObj->Id, p->nSatVars );
+ Ivy_ObjSetSatNum( pObj, p->nSatVars++ );
+ if ( Ivy_ObjIsNode(pObj) )
+ Vec_PtrPush( vFrontier, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the solver clause database.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_FraigNodeAddToSolver( Ivy_FraigMan_t * p, Ivy_Obj_t * pOld, Ivy_Obj_t * pNew )
+{
+ Vec_Ptr_t * vFrontier, * vFanins;
+ Ivy_Obj_t * pNode, * pFanin;
+ int i, k, fUseMuxes = 1;
+ assert( pOld || pNew );
+ // quit if CNF is ready
+ if ( (!pOld || Ivy_ObjFaninVec(pOld)) && (!pNew || Ivy_ObjFaninVec(pNew)) )
+ return;
+ // start the frontier
+ vFrontier = Vec_PtrAlloc( 100 );
+ if ( pOld ) Ivy_FraigObjAddToFrontier( p, pOld, vFrontier );
+ if ( pNew ) Ivy_FraigObjAddToFrontier( p, pNew, vFrontier );
+ // explore nodes in the frontier
+ Vec_PtrForEachEntry( vFrontier, pNode, i )
+ {
+ // create the supergate
+ assert( Ivy_ObjSatNum(pNode) );
+ assert( Ivy_ObjFaninVec(pNode) == NULL );
+ if ( fUseMuxes && Ivy_ObjIsMuxType(pNode) )
+ {
+ vFanins = Vec_PtrAlloc( 4 );
+ Vec_PtrPushUnique( vFanins, Ivy_ObjFanin0( Ivy_ObjFanin0(pNode) ) );
+ Vec_PtrPushUnique( vFanins, Ivy_ObjFanin0( Ivy_ObjFanin1(pNode) ) );
+ Vec_PtrPushUnique( vFanins, Ivy_ObjFanin1( Ivy_ObjFanin0(pNode) ) );
+ Vec_PtrPushUnique( vFanins, Ivy_ObjFanin1( Ivy_ObjFanin1(pNode) ) );
+ Vec_PtrForEachEntry( vFanins, pFanin, k )
+ Ivy_FraigObjAddToFrontier( p, Ivy_Regular(pFanin), vFrontier );
+ Ivy_FraigAddClausesMux( p, pNode );
+ }
+ else
+ {
+ vFanins = Ivy_FraigCollectSuper( pNode, fUseMuxes );
+ Vec_PtrForEachEntry( vFanins, pFanin, k )
+ Ivy_FraigObjAddToFrontier( p, Ivy_Regular(pFanin), vFrontier );
+ Ivy_FraigAddClausesSuper( p, pNode, vFanins );
+ }
+ assert( Vec_PtrSize(vFanins) > 1 );
+ Ivy_ObjSetFaninVec( pNode, vFanins );
+ }
+ Vec_PtrFree( vFrontier );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets variable activities in the cone.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigSetActivityFactors_rec( Ivy_FraigMan_t * p, Ivy_Obj_t * pObj, int LevelMin, int LevelMax )
+{
+ Vec_Ptr_t * vFanins;
+ Ivy_Obj_t * pFanin;
+ int i, Counter = 0;
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjSatNum(pObj) );
+ // skip visited variables
+ if ( Ivy_ObjIsTravIdCurrent(p->pManFraig, pObj) )
+ return 0;
+ Ivy_ObjSetTravIdCurrent(p->pManFraig, pObj);
+ // add the PI to the list
+ if ( pObj->Level <= (unsigned)LevelMin || Ivy_ObjIsPi(pObj) )
+ return 0;
+ // set the factor of this variable
+ // (LevelMax-LevelMin) / (pObj->Level-LevelMin) = p->pParams->dActConeBumpMax / ThisBump
+ p->pSat->factors[Ivy_ObjSatNum(pObj)] = p->pParams->dActConeBumpMax * (pObj->Level - LevelMin)/(LevelMax - LevelMin);
+ veci_push(&p->pSat->act_vars, Ivy_ObjSatNum(pObj));
+ // explore the fanins
+ vFanins = Ivy_ObjFaninVec( pObj );
+ Vec_PtrForEachEntry( vFanins, pFanin, i )
+ Counter += Ivy_FraigSetActivityFactors_rec( p, Ivy_Regular(pFanin), LevelMin, LevelMax );
+ return 1 + Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets variable activities in the cone.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigSetActivityFactors( Ivy_FraigMan_t * p, Ivy_Obj_t * pOld, Ivy_Obj_t * pNew )
+{
+ int clk, LevelMin, LevelMax;
+ assert( pOld || pNew );
+clk = clock();
+ // reset the active variables
+ veci_resize(&p->pSat->act_vars, 0);
+ // prepare for traversal
+ Ivy_ManIncrementTravId( p->pManFraig );
+ // determine the min and max level to visit
+ assert( p->pParams->dActConeRatio > 0 && p->pParams->dActConeRatio < 1 );
+ LevelMax = IVY_MAX( (pNew ? pNew->Level : 0), (pOld ? pOld->Level : 0) );
+ LevelMin = (int)(LevelMax * (1.0 - p->pParams->dActConeRatio));
+ // traverse
+ if ( pOld && !Ivy_ObjIsConst1(pOld) )
+ Ivy_FraigSetActivityFactors_rec( p, pOld, LevelMin, LevelMax );
+ if ( pNew && !Ivy_ObjIsConst1(pNew) )
+ Ivy_FraigSetActivityFactors_rec( p, pNew, LevelMin, LevelMax );
+//Ivy_FraigPrintActivity( p );
+p->timeTrav += clock() - clk;
+ return 1;
+}
+
+
+
+#include "cuddInt.h"
+
+/**Function*************************************************************
+
+ Synopsis [Checks equivalence using BDDs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+DdNode * Ivy_FraigNodesAreEquivBdd_int( DdManager * dd, DdNode * bFunc, Vec_Ptr_t * vFront, int Level )
+{
+ DdNode ** pFuncs;
+ DdNode * bFuncNew;
+ Vec_Ptr_t * vTemp;
+ Ivy_Obj_t * pObj, * pFanin;
+ int i, NewSize;
+ // create new frontier
+ vTemp = Vec_PtrAlloc( 100 );
+ Vec_PtrForEachEntry( vFront, pObj, i )
+ {
+ if ( (int)pObj->Level != Level )
+ {
+ pObj->fMarkB = 1;
+ pObj->TravId = Vec_PtrSize(vTemp);
+ Vec_PtrPush( vTemp, pObj );
+ continue;
+ }
+
+ pFanin = Ivy_ObjFanin0(pObj);
+ if ( pFanin->fMarkB == 0 )
+ {
+ pFanin->fMarkB = 1;
+ pFanin->TravId = Vec_PtrSize(vTemp);
+ Vec_PtrPush( vTemp, pFanin );
+ }
+
+ pFanin = Ivy_ObjFanin1(pObj);
+ if ( pFanin->fMarkB == 0 )
+ {
+ pFanin->fMarkB = 1;
+ pFanin->TravId = Vec_PtrSize(vTemp);
+ Vec_PtrPush( vTemp, pFanin );
+ }
+ }
+ // collect the permutation
+ NewSize = IVY_MAX(dd->size, Vec_PtrSize(vTemp));
+ pFuncs = ALLOC( DdNode *, NewSize );
+ Vec_PtrForEachEntry( vFront, pObj, i )
+ {
+ if ( (int)pObj->Level != Level )
+ pFuncs[i] = Cudd_bddIthVar( dd, pObj->TravId );
+ else
+ pFuncs[i] = Cudd_bddAnd( dd,
+ Cudd_NotCond( Cudd_bddIthVar(dd, Ivy_ObjFanin0(pObj)->TravId), Ivy_ObjFaninC0(pObj) ),
+ Cudd_NotCond( Cudd_bddIthVar(dd, Ivy_ObjFanin1(pObj)->TravId), Ivy_ObjFaninC1(pObj) ) );
+ Cudd_Ref( pFuncs[i] );
+ }
+ // add the remaining vars
+ assert( NewSize == dd->size );
+ for ( i = Vec_PtrSize(vFront); i < dd->size; i++ )
+ {
+ pFuncs[i] = Cudd_bddIthVar( dd, i );
+ Cudd_Ref( pFuncs[i] );
+ }
+
+ // create new
+ bFuncNew = Cudd_bddVectorCompose( dd, bFunc, pFuncs ); Cudd_Ref( bFuncNew );
+ // clean trav Id
+ Vec_PtrForEachEntry( vTemp, pObj, i )
+ {
+ pObj->fMarkB = 0;
+ pObj->TravId = 0;
+ }
+ // deref
+ for ( i = 0; i < dd->size; i++ )
+ Cudd_RecursiveDeref( dd, pFuncs[i] );
+ free( pFuncs );
+
+ free( vFront->pArray );
+ *vFront = *vTemp;
+
+ vTemp->nCap = vTemp->nSize = 0;
+ vTemp->pArray = NULL;
+ Vec_PtrFree( vTemp );
+
+ Cudd_Deref( bFuncNew );
+ return bFuncNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks equivalence using BDDs.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_FraigNodesAreEquivBdd( Ivy_Obj_t * pObj1, Ivy_Obj_t * pObj2 )
+{
+ static DdManager * dd = NULL;
+ DdNode * bFunc, * bTemp;
+ Vec_Ptr_t * vFront;
+ Ivy_Obj_t * pObj;
+ int i, RetValue, Iter, Level;
+ // start the manager
+ if ( dd == NULL )
+ dd = Cudd_Init( 50, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 );
+ // create front
+ vFront = Vec_PtrAlloc( 100 );
+ Vec_PtrPush( vFront, pObj1 );
+ Vec_PtrPush( vFront, pObj2 );
+ // get the function
+ bFunc = Cudd_bddXor( dd, Cudd_bddIthVar(dd,0), Cudd_bddIthVar(dd,1) ); Cudd_Ref( bFunc );
+ bFunc = Cudd_NotCond( bFunc, pObj1->fPhase != pObj2->fPhase );
+ // try running BDDs
+ for ( Iter = 0; ; Iter++ )
+ {
+ // find max level
+ Level = 0;
+ Vec_PtrForEachEntry( vFront, pObj, i )
+ if ( Level < (int)pObj->Level )
+ Level = (int)pObj->Level;
+ if ( Level == 0 )
+ break;
+ bFunc = Ivy_FraigNodesAreEquivBdd_int( dd, bTemp = bFunc, vFront, Level ); Cudd_Ref( bFunc );
+ Cudd_RecursiveDeref( dd, bTemp );
+ if ( bFunc == Cudd_ReadLogicZero(dd) ) // proved
+ {printf( "%d", Iter ); break;}
+ if ( Cudd_DagSize(bFunc) > 1000 )
+ {printf( "b" ); break;}
+ if ( dd->size > 120 )
+ {printf( "s" ); break;}
+ if ( Iter > 50 )
+ {printf( "i" ); break;}
+ }
+ if ( bFunc == Cudd_ReadLogicZero(dd) ) // unsat
+ RetValue = 1;
+ else if ( Level == 0 ) // sat
+ RetValue = 0;
+ else
+ RetValue = -1; // spaceout/timeout
+ Cudd_RecursiveDeref( dd, bFunc );
+ Vec_PtrFree( vFront );
+ return RetValue;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyHaig.c b/src/aig/ivy/ivyHaig.c
new file mode 100644
index 00000000..87021600
--- /dev/null
+++ b/src/aig/ivy/ivyHaig.c
@@ -0,0 +1,530 @@
+/**CFile****************************************************************
+
+ FileName [ivyHaig.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [HAIG management procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyHaig.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/*
+ HAIGing rules in working AIG:
+ - Each node in the working AIG has a pointer to the corresponding node in HAIG
+ (this node is not necessarily the representative of the equivalence class of HAIG nodes)
+ - This pointer is complemented if the AIG node and its corresponding HAIG node have different phase
+
+ Choice node rules in HAIG:
+ - Equivalent nodes are linked into a ring
+ - Exactly one node in the ring has fanouts (this node is called the representative)
+ - The pointer going from a node to the next node in the ring is complemented
+ if the first node is complemented, compared to the representative node of the equivalence class
+ - (consequence of the above) The representative node always has non-complemented pointer to the next node
+ - New nodes are inserted into the ring immediately after the representative node
+*/
+
+// returns the representative node of the given HAIG node
+static inline Ivy_Obj_t * Ivy_HaigObjRepr( Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pTemp;
+ assert( !Ivy_IsComplement(pObj) );
+ // if the node has no equivalent node or has fanout, it is representative
+ if ( pObj->pEquiv == NULL || Ivy_ObjRefs(pObj) > 0 )
+ return pObj;
+ // the node belongs to a class and is not a representative
+ // complemented edge (pObj->pEquiv) tells if it is complemented w.r.t. the repr
+ for ( pTemp = Ivy_Regular(pObj->pEquiv); pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ if ( Ivy_ObjRefs(pTemp) > 0 )
+ break;
+ // return the representative node
+ assert( Ivy_ObjRefs(pTemp) > 0 );
+ return Ivy_NotCond( pTemp, Ivy_IsComplement(pObj->pEquiv) );
+}
+
+// counts the number of nodes in the equivalence class
+static inline int Ivy_HaigObjCountClass( Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pTemp;
+ int Counter;
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjRefs(pObj) > 0 );
+ if ( pObj->pEquiv == NULL )
+ return 1;
+ assert( !Ivy_IsComplement(pObj->pEquiv) );
+ Counter = 1;
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ Counter++;
+ return Counter;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts HAIG for the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigStart( Ivy_Man_t * p, int fVerbose )
+{
+ Vec_Int_t * vLatches;
+ Ivy_Obj_t * pObj;
+ int i;
+ assert( p->pHaig == NULL );
+ p->pHaig = Ivy_ManDup( p );
+
+ if ( fVerbose )
+ {
+ printf( "Starting : " );
+ Ivy_ManPrintStats( p->pHaig );
+ }
+
+ // collect latches of design D and set their values to be DC
+ vLatches = Vec_IntAlloc( 100 );
+ Ivy_ManForEachLatch( p->pHaig, pObj, i )
+ {
+ pObj->Init = IVY_INIT_DC;
+ Vec_IntPush( vLatches, pObj->Id );
+ }
+ p->pHaig->pData = vLatches;
+/*
+ {
+ int x;
+ Ivy_ManShow( p, 0, NULL );
+ Ivy_ManShow( p->pHaig, 1, NULL );
+ x = 0;
+ }
+*/
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transfers the HAIG to the newly created manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigTrasfer( Ivy_Man_t * p, Ivy_Man_t * pNew )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ assert( p->pHaig != NULL );
+ Ivy_ManConst1(pNew)->pEquiv = Ivy_ManConst1(p)->pEquiv;
+ Ivy_ManForEachPi( pNew, pObj, i )
+ pObj->pEquiv = Ivy_ManPi( p, i )->pEquiv;
+ pNew->pHaig = p->pHaig;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops HAIG for the manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigStop( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ assert( p->pHaig != NULL );
+ Vec_IntFree( p->pHaig->pData );
+ Ivy_ManStop( p->pHaig );
+ p->pHaig = NULL;
+ // remove dangling pointers to the HAIG objects
+ Ivy_ManForEachObj( p, pObj, i )
+ pObj->pEquiv = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Creates a new node in HAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigCreateObj( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pEquiv0, * pEquiv1;
+ assert( p->pHaig != NULL );
+ assert( !Ivy_IsComplement(pObj) );
+ if ( Ivy_ObjType(pObj) == IVY_BUF )
+ pObj->pEquiv = Ivy_ObjChild0Equiv(pObj);
+ else if ( Ivy_ObjType(pObj) == IVY_LATCH )
+ {
+// pObj->pEquiv = Ivy_Latch( p->pHaig, Ivy_ObjChild0Equiv(pObj), pObj->Init );
+ pEquiv0 = Ivy_ObjChild0Equiv(pObj);
+ pEquiv0 = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pEquiv0)), Ivy_IsComplement(pEquiv0) );
+ pObj->pEquiv = Ivy_Latch( p->pHaig, pEquiv0, pObj->Init );
+ }
+ else if ( Ivy_ObjType(pObj) == IVY_AND )
+ {
+// pObj->pEquiv = Ivy_And( p->pHaig, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) );
+ pEquiv0 = Ivy_ObjChild0Equiv(pObj);
+ pEquiv0 = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pEquiv0)), Ivy_IsComplement(pEquiv0) );
+ pEquiv1 = Ivy_ObjChild1Equiv(pObj);
+ pEquiv1 = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pEquiv1)), Ivy_IsComplement(pEquiv1) );
+ pObj->pEquiv = Ivy_And( p->pHaig, pEquiv0, pEquiv1 );
+ }
+ else assert( 0 );
+ // make sure the node points to the representative
+// pObj->pEquiv = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pObj->pEquiv)), Ivy_IsComplement(pObj->pEquiv) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if the old node is in the TFI of the new node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ObjIsInTfi_rec( Ivy_Obj_t * pObjNew, Ivy_Obj_t * pObjOld, int Levels )
+{
+ if ( pObjNew == pObjOld )
+ return 1;
+ if ( Levels == 0 || Ivy_ObjIsCi(pObjNew) || Ivy_ObjIsConst1(pObjNew) )
+ return 0;
+ if ( Ivy_ObjIsInTfi_rec( Ivy_ObjFanin0(pObjNew), pObjOld, Levels - 1 ) )
+ return 1;
+ if ( Ivy_ObjIsNode(pObjNew) && Ivy_ObjIsInTfi_rec( Ivy_ObjFanin1(pObjNew), pObjOld, Levels - 1 ) )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the pair of equivalent nodes in HAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigCreateChoice( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew )
+{
+ Ivy_Obj_t * pObjOldHaig, * pObjNewHaig;
+ Ivy_Obj_t * pObjOldHaigR, * pObjNewHaigR;
+ int fCompl;
+//printf( "\nCreating choice for %d and %d in AIG\n", pObjOld->Id, Ivy_Regular(pObjNew)->Id );
+
+ assert( p->pHaig != NULL );
+ assert( !Ivy_IsComplement(pObjOld) );
+ // get pointers to the representatives of pObjOld and pObjNew
+ pObjOldHaig = pObjOld->pEquiv;
+ pObjNewHaig = Ivy_NotCond( Ivy_Regular(pObjNew)->pEquiv, Ivy_IsComplement(pObjNew) );
+ // get the classes
+ pObjOldHaig = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pObjOldHaig)), Ivy_IsComplement(pObjOldHaig) );
+ pObjNewHaig = Ivy_NotCond( Ivy_HaigObjRepr(Ivy_Regular(pObjNewHaig)), Ivy_IsComplement(pObjNewHaig) );
+ // get regular pointers
+ pObjOldHaigR = Ivy_Regular(pObjOldHaig);
+ pObjNewHaigR = Ivy_Regular(pObjNewHaig);
+ // check if there is phase difference between them
+ fCompl = (Ivy_IsComplement(pObjOldHaig) != Ivy_IsComplement(pObjNewHaig));
+ // if the class is the same, nothing to do
+ if ( pObjOldHaigR == pObjNewHaigR )
+ return;
+ // if the second node belongs to a class, do not merge classes (for the time being)
+ if ( Ivy_ObjRefs(pObjOldHaigR) == 0 || pObjNewHaigR->pEquiv != NULL ||
+ Ivy_ObjRefs(pObjNewHaigR) > 0 ) //|| Ivy_ObjIsInTfi_rec(pObjNewHaigR, pObjOldHaigR, 10) )
+ {
+/*
+ if ( pObjNewHaigR->pEquiv != NULL )
+ printf( "c" );
+ if ( Ivy_ObjRefs(pObjNewHaigR) > 0 )
+ printf( "f" );
+ printf( " " );
+*/
+ p->pHaig->nClassesSkip++;
+ return;
+ }
+
+ // add this node to the class of pObjOldHaig
+ assert( Ivy_ObjRefs(pObjOldHaigR) > 0 );
+ assert( !Ivy_IsComplement(pObjOldHaigR->pEquiv) );
+ if ( pObjOldHaigR->pEquiv == NULL )
+ pObjNewHaigR->pEquiv = Ivy_NotCond( pObjOldHaigR, fCompl );
+ else
+ pObjNewHaigR->pEquiv = Ivy_NotCond( pObjOldHaigR->pEquiv, fCompl );
+ pObjOldHaigR->pEquiv = pObjNewHaigR;
+//printf( "Setting choice node %d -> %d.\n", pObjOldHaigR->Id, pObjNewHaigR->Id );
+ // update the class of the new node
+// Ivy_Regular(pObjNew)->pEquiv = Ivy_NotCond( pObjOldHaigR, fCompl ^ Ivy_IsComplement(pObjNew) );
+//printf( "Creating choice for %d and %d in HAIG\n", pObjOldHaigR->Id, pObjNewHaigR->Id );
+
+// if ( pObjOldHaigR->Id == 13 )
+// {
+// Ivy_ManShow( p, 0 );
+// Ivy_ManShow( p->pHaig, 1 );
+// }
+// if ( !Ivy_ManIsAcyclic( p->pHaig ) )
+// printf( "HAIG contains a cycle\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of choices and choice nodes in HAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManHaigCountChoices( Ivy_Man_t * p, int * pnChoices )
+{
+ Ivy_Obj_t * pObj;
+ int nChoices, nChoiceNodes, Counter, i;
+ assert( p->pHaig != NULL );
+ nChoices = nChoiceNodes = 0;
+ Ivy_ManForEachObj( p->pHaig, pObj, i )
+ {
+ if ( Ivy_ObjIsTerm(pObj) || i == 0 )
+ continue;
+ if ( Ivy_ObjRefs(pObj) == 0 )
+ continue;
+ Counter = Ivy_HaigObjCountClass( pObj );
+ nChoiceNodes += (int)(Counter > 1);
+ nChoices += Counter - 1;
+// if ( Counter > 1 )
+// printf( "Choice node %d %s\n", pObj->Id, Ivy_ObjIsLatch(pObj)? "(latch)": "" );
+ }
+ *pnChoices = nChoices;
+ return nChoiceNodes;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints statistics of the HAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigPostprocess( Ivy_Man_t * p, int fVerbose )
+{
+ int nChoices, nChoiceNodes;
+
+ assert( p->pHaig != NULL );
+
+ if ( fVerbose )
+ {
+ printf( "Final : " );
+ Ivy_ManPrintStats( p );
+ printf( "HAIG : " );
+ Ivy_ManPrintStats( p->pHaig );
+
+ // print choice node stats
+ nChoiceNodes = Ivy_ManHaigCountChoices( p, &nChoices );
+ printf( "Total choice nodes = %d. Total choices = %d. Skipped classes = %d.\n",
+ nChoiceNodes, nChoices, p->pHaig->nClassesSkip );
+ }
+
+ if ( Ivy_ManIsAcyclic( p->pHaig ) )
+ {
+ if ( fVerbose )
+ printf( "HAIG is acyclic\n" );
+ }
+ else
+ printf( "HAIG contains a cycle\n" );
+
+// if ( fVerbose )
+// Ivy_ManHaigSimulate( p );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Applies the simulation rules.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Ivy_Init_t Ivy_ManHaigSimulateAnd( Ivy_Init_t In0, Ivy_Init_t In1 )
+{
+ assert( In0 != IVY_INIT_NONE && In1 != IVY_INIT_NONE );
+ if ( In0 == IVY_INIT_DC || In1 == IVY_INIT_DC )
+ return IVY_INIT_DC;
+ if ( In0 == IVY_INIT_1 && In1 == IVY_INIT_1 )
+ return IVY_INIT_1;
+ return IVY_INIT_0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Applies the simulation rules.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline Ivy_Init_t Ivy_ManHaigSimulateChoice( Ivy_Init_t In0, Ivy_Init_t In1 )
+{
+ assert( In0 != IVY_INIT_NONE && In1 != IVY_INIT_NONE );
+ if ( (In0 == IVY_INIT_0 && In1 == IVY_INIT_1) || (In0 == IVY_INIT_1 && In1 == IVY_INIT_0) )
+ {
+ printf( "Compatibility fails.\n" );
+ return IVY_INIT_0;
+ }
+ if ( In0 == IVY_INIT_DC && In1 == IVY_INIT_DC )
+ return IVY_INIT_DC;
+ if ( In0 != IVY_INIT_DC )
+ return In0;
+ return In1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Simulate HAIG using modified 3-valued simulation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManHaigSimulate( Ivy_Man_t * p )
+{
+ Vec_Int_t * vNodes, * vLatches, * vLatchesD;
+ Ivy_Obj_t * pObj, * pTemp;
+ Ivy_Init_t In0, In1;
+ int i, k, Counter;
+ int fVerbose = 0;
+
+ // check choices
+ Ivy_ManCheckChoices( p );
+
+ // switch to HAIG
+ assert( p->pHaig != NULL );
+ p = p->pHaig;
+
+if ( fVerbose )
+Ivy_ManForEachPi( p, pObj, i )
+printf( "Setting PI %d\n", pObj->Id );
+
+ // collect latches and nodes in the DFS order
+ vNodes = Ivy_ManDfsSeq( p, &vLatches );
+
+if ( fVerbose )
+Ivy_ManForEachNodeVec( p, vNodes, pObj, i )
+printf( "Collected node %d with fanins %d and %d\n", pObj->Id, Ivy_ObjFanin0(pObj)->Id, Ivy_ObjFanin1(pObj)->Id );
+
+ // set the PI values
+ Ivy_ManConst1(p)->Init = IVY_INIT_1;
+ Ivy_ManForEachPi( p, pObj, i )
+ pObj->Init = IVY_INIT_0;
+
+ // set the latch values
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ pObj->Init = IVY_INIT_DC;
+ // set the latches of D to be determinate
+ vLatchesD = p->pData;
+ Ivy_ManForEachNodeVec( p, vLatchesD, pObj, i )
+ pObj->Init = IVY_INIT_0;
+
+ // perform several rounds of simulation
+ for ( k = 0; k < 10; k++ )
+ {
+ // count the number of non-determinate values
+ Counter = 0;
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ Counter += ( pObj->Init == IVY_INIT_DC );
+ printf( "Iter %d : Non-determinate = %d\n", k, Counter );
+
+ // simulate the internal nodes
+ Ivy_ManForEachNodeVec( p, vNodes, pObj, i )
+ {
+if ( fVerbose )
+printf( "Processing node %d with fanins %d and %d\n", pObj->Id, Ivy_ObjFanin0(pObj)->Id, Ivy_ObjFanin1(pObj)->Id );
+ In0 = Ivy_InitNotCond( Ivy_ObjFanin0(pObj)->Init, Ivy_ObjFaninC0(pObj) );
+ In1 = Ivy_InitNotCond( Ivy_ObjFanin1(pObj)->Init, Ivy_ObjFaninC1(pObj) );
+ pObj->Init = Ivy_ManHaigSimulateAnd( In0, In1 );
+ // simulate the equivalence class if the node is a representative
+ if ( pObj->pEquiv && Ivy_ObjRefs(pObj) > 0 )
+ {
+if ( fVerbose )
+printf( "Processing choice node %d\n", pObj->Id );
+ In0 = pObj->Init;
+ assert( !Ivy_IsComplement(pObj->pEquiv) );
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ {
+if ( fVerbose )
+printf( "Processing secondary node %d\n", pTemp->Id );
+ In1 = Ivy_InitNotCond( pTemp->Init, Ivy_IsComplement(pTemp->pEquiv) );
+ In0 = Ivy_ManHaigSimulateChoice( In0, In1 );
+ }
+ pObj->Init = In0;
+ }
+ }
+
+ // simulate the latches
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ {
+ pObj->Level = Ivy_ObjFanin0(pObj)->Init;
+if ( fVerbose )
+printf( "Using latch %d with fanin %d\n", pObj->Id, Ivy_ObjFanin0(pObj)->Id );
+ }
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ pObj->Init = pObj->Level, pObj->Level = 0;
+ }
+ // free arrays
+ Vec_IntFree( vNodes );
+ Vec_IntFree( vLatches );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyMan.c b/src/aig/ivy/ivyMan.c
new file mode 100644
index 00000000..07faef85
--- /dev/null
+++ b/src/aig/ivy/ivyMan.c
@@ -0,0 +1,546 @@
+/**CFile****************************************************************
+
+ FileName [ivyMan.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [AIG manager.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivy_.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManStart()
+{
+ Ivy_Man_t * p;
+ // start the manager
+ p = ALLOC( Ivy_Man_t, 1 );
+ memset( p, 0, sizeof(Ivy_Man_t) );
+ // perform initializations
+ p->Ghost.Id = -1;
+ p->nTravIds = 1;
+ p->fCatchExor = 1;
+ // allocate arrays for nodes
+ p->vPis = Vec_PtrAlloc( 100 );
+ p->vPos = Vec_PtrAlloc( 100 );
+ p->vBufs = Vec_PtrAlloc( 100 );
+ p->vObjs = Vec_PtrAlloc( 100 );
+ // prepare the internal memory manager
+ Ivy_ManStartMemory( p );
+ // create the constant node
+ p->pConst1 = Ivy_ManFetchMemory( p );
+ p->pConst1->fPhase = 1;
+ Vec_PtrPush( p->vObjs, p->pConst1 );
+ p->nCreated = 1;
+ // start the table
+ p->nTableSize = 10007;
+ p->pTable = ALLOC( int, p->nTableSize );
+ memset( p->pTable, 0, sizeof(int) * p->nTableSize );
+ return p;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManStartFrom( Ivy_Man_t * p )
+{
+ Ivy_Man_t * pNew;
+ Ivy_Obj_t * pObj;
+ int i;
+ // create the new manager
+ pNew = Ivy_ManStart();
+ // create the PIs
+ Ivy_ManConst1(p)->pEquiv = Ivy_ManConst1(pNew);
+ Ivy_ManForEachPi( p, pObj, i )
+ pObj->pEquiv = Ivy_ObjCreatePi(pNew);
+ return pNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Duplicates the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManDup( Ivy_Man_t * p )
+{
+ Vec_Int_t * vNodes, * vLatches;
+ Ivy_Man_t * pNew;
+ Ivy_Obj_t * pObj;
+ int i;
+ // collect latches and nodes in the DFS order
+ vNodes = Ivy_ManDfsSeq( p, &vLatches );
+ // create the new manager
+ pNew = Ivy_ManStart();
+ // create the PIs
+ Ivy_ManConst1(p)->pEquiv = Ivy_ManConst1(pNew);
+ Ivy_ManForEachPi( p, pObj, i )
+ pObj->pEquiv = Ivy_ObjCreatePi(pNew);
+ // create the fake PIs for latches
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ pObj->pEquiv = Ivy_ObjCreatePi(pNew);
+ // duplicate internal nodes
+ Ivy_ManForEachNodeVec( p, vNodes, pObj, i )
+ if ( Ivy_ObjIsBuf(pObj) )
+ pObj->pEquiv = Ivy_ObjChild0Equiv(pObj);
+ else
+ pObj->pEquiv = Ivy_And( pNew, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) );
+ // add the POs
+ Ivy_ManForEachPo( p, pObj, i )
+ Ivy_ObjCreatePo( pNew, Ivy_ObjChild0Equiv(pObj) );
+ // transform additional PI nodes into latches and connect them
+ Ivy_ManForEachNodeVec( p, vLatches, pObj, i )
+ {
+ assert( !Ivy_ObjFaninC0(pObj) );
+ pObj->pEquiv->Type = IVY_LATCH;
+ pObj->pEquiv->Init = pObj->Init;
+ Ivy_ObjConnect( pNew, pObj->pEquiv, Ivy_ObjChild0Equiv(pObj), NULL );
+ }
+ // shrink the arrays
+ Vec_PtrShrink( pNew->vPis, Ivy_ManPiNum(p) );
+ // update the counters of different objects
+ pNew->nObjs[IVY_PI] -= Ivy_ManLatchNum(p);
+ pNew->nObjs[IVY_LATCH] += Ivy_ManLatchNum(p);
+ // free arrays
+ Vec_IntFree( vNodes );
+ Vec_IntFree( vLatches );
+ // make sure structural hashing did not change anything
+ assert( Ivy_ManNodeNum(p) == Ivy_ManNodeNum(pNew) );
+ assert( Ivy_ManLatchNum(p) == Ivy_ManLatchNum(pNew) );
+ // check the resulting network
+ if ( !Ivy_ManCheck(pNew) )
+ printf( "Ivy_ManMakeSeq(): The check has failed.\n" );
+ return pNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManFrames( Ivy_Man_t * pMan, int nLatches, int nFrames, int fInit, Vec_Ptr_t ** pvMapping )
+{
+ Vec_Ptr_t * vMapping;
+ Ivy_Man_t * pNew;
+ Ivy_Obj_t * pObj;
+ int i, f, nPis, nPos, nIdMax;
+ assert( Ivy_ManLatchNum(pMan) == 0 );
+ assert( nFrames > 0 );
+ // prepare the mapping
+ nPis = Ivy_ManPiNum(pMan) - nLatches;
+ nPos = Ivy_ManPoNum(pMan) - nLatches;
+ nIdMax = Ivy_ManObjIdMax(pMan);
+ // create the new manager
+ pNew = Ivy_ManStart();
+ // set the starting values of latch inputs
+ for ( i = 0; i < nLatches; i++ )
+ Ivy_ManPo(pMan, nPos+i)->pEquiv = fInit? Ivy_Not(Ivy_ManConst1(pNew)) : Ivy_ObjCreatePi(pNew);
+ // add timeframes
+ vMapping = Vec_PtrStart( nIdMax * nFrames + 1 );
+ for ( f = 0; f < nFrames; f++ )
+ {
+ // create PIs
+ Ivy_ManConst1(pMan)->pEquiv = Ivy_ManConst1(pNew);
+ for ( i = 0; i < nPis; i++ )
+ Ivy_ManPi(pMan, i)->pEquiv = Ivy_ObjCreatePi(pNew);
+ // transfer values to latch outputs
+ for ( i = 0; i < nLatches; i++ )
+ Ivy_ManPi(pMan, nPis+i)->pEquiv = Ivy_ManPo(pMan, nPos+i)->pEquiv;
+ // perform strashing
+ Ivy_ManForEachNode( pMan, pObj, i )
+ pObj->pEquiv = Ivy_And( pNew, Ivy_ObjChild0Equiv(pObj), Ivy_ObjChild1Equiv(pObj) );
+ // create POs
+ for ( i = 0; i < nPos; i++ )
+ Ivy_ManPo(pMan, i)->pEquiv = Ivy_ObjCreatePo( pNew, Ivy_ObjChild0Equiv(Ivy_ManPo(pMan, i)) );
+ // set the results of latch inputs
+ for ( i = 0; i < nLatches; i++ )
+ Ivy_ManPo(pMan, nPos+i)->pEquiv = Ivy_ObjChild0Equiv(Ivy_ManPo(pMan, nPos+i));
+ // save the pointers in this frame
+ Ivy_ManForEachObj( pMan, pObj, i )
+ Vec_PtrWriteEntry( vMapping, f * nIdMax + i, pObj->pEquiv );
+ }
+ // connect latches
+ if ( !fInit )
+ for ( i = 0; i < nLatches; i++ )
+ Ivy_ObjCreatePo( pNew, Ivy_ManPo(pMan, nPos+i)->pEquiv );
+ // remove dangling nodes
+ Ivy_ManCleanup(pNew);
+ *pvMapping = vMapping;
+ // check the resulting network
+ if ( !Ivy_ManCheck(pNew) )
+ printf( "Ivy_ManFrames(): The check has failed.\n" );
+ return pNew;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Stops the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManStop( Ivy_Man_t * p )
+{
+ if ( p->time1 ) { PRT( "Update lev ", p->time1 ); }
+ if ( p->time2 ) { PRT( "Update levR ", p->time2 ); }
+// Ivy_TableProfile( 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 );
+ if ( p->vPos ) Vec_PtrFree( p->vPos );
+ if ( p->vBufs ) Vec_PtrFree( p->vBufs );
+ if ( p->vObjs ) Vec_PtrFree( p->vObjs );
+ free( p->pTable );
+ free( p );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes nodes without fanout.]
+
+ Description [Returns the number of dangling nodes removed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManCleanup( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pNode;
+ int i, nNodesOld;
+ nNodesOld = Ivy_ManNodeNum(p);
+ Ivy_ManForEachObj( p, pNode, i )
+ if ( Ivy_ObjIsNode(pNode) || Ivy_ObjIsLatch(pNode) || Ivy_ObjIsBuf(pNode) )
+ if ( Ivy_ObjRefs(pNode) == 0 )
+ Ivy_ObjDelete_rec( p, pNode, 1 );
+//printf( "Cleanup removed %d nodes.\n", nNodesOld - Ivy_ManNodeNum(p) );
+ return nNodesOld - Ivy_ManNodeNum(p);
+}
+
+/**Function*************************************************************
+
+ Synopsis [Marks nodes reachable from the given one.]
+
+ Description [Returns the number of dangling nodes removed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCleanupSeq_rec( Ivy_Obj_t * pObj )
+{
+ if ( Ivy_ObjIsMarkA(pObj) )
+ return;
+ Ivy_ObjSetMarkA(pObj);
+ if ( pObj->pFanin0 != NULL )
+ Ivy_ManCleanupSeq_rec( Ivy_ObjFanin0(pObj) );
+ if ( pObj->pFanin1 != NULL )
+ Ivy_ManCleanupSeq_rec( Ivy_ObjFanin1(pObj) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Removes logic that does not feed into POs.]
+
+ Description [Returns the number of dangling nodes removed.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManCleanupSeq( Ivy_Man_t * p )
+{
+ Vec_Ptr_t * vNodes;
+ Ivy_Obj_t * pObj;
+ int i, RetValue;
+ // mark the constant and PIs
+ Ivy_ObjSetMarkA( Ivy_ManConst1(p) );
+ Ivy_ManForEachPi( p, pObj, i )
+ Ivy_ObjSetMarkA( pObj );
+ // mark nodes visited from POs
+ Ivy_ManForEachPo( p, pObj, i )
+ Ivy_ManCleanupSeq_rec( pObj );
+ // collect unmarked nodes
+ vNodes = Vec_PtrAlloc( 100 );
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ if ( Ivy_ObjIsMarkA(pObj) )
+ Ivy_ObjClearMarkA(pObj);
+ else
+ Vec_PtrPush( vNodes, pObj );
+ }
+ if ( Vec_PtrSize(vNodes) == 0 )
+ {
+ Vec_PtrFree( vNodes );
+//printf( "Sequential sweep cleaned out %d nodes.\n", 0 );
+ return 0;
+ }
+ // disconnect the marked objects
+ Vec_PtrForEachEntry( vNodes, pObj, i )
+ Ivy_ObjDisconnect( p, pObj );
+ // remove the dangling objects
+ Vec_PtrForEachEntry( vNodes, pObj, i )
+ {
+ assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsLatch(pObj) || Ivy_ObjIsBuf(pObj) );
+ assert( Ivy_ObjRefs(pObj) == 0 );
+ // update node counters of the manager
+ p->nObjs[pObj->Type]--;
+ p->nDeleted++;
+ // delete buffer from the array of buffers
+ if ( p->fFanout && Ivy_ObjIsBuf(pObj) )
+ Vec_PtrRemove( p->vBufs, pObj );
+ // free the node
+ Vec_PtrWriteEntry( p->vObjs, pObj->Id, NULL );
+ Ivy_ManRecycleMemory( p, pObj );
+ }
+ // return the number of nodes freed
+ RetValue = Vec_PtrSize(vNodes);
+ Vec_PtrFree( vNodes );
+//printf( "Sequential sweep cleaned out %d nodes.\n", RetValue );
+ return RetValue;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Checks if latches form self-loop.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManLatchIsSelfFeed_rec( Ivy_Obj_t * pLatch, Ivy_Obj_t * pLatchRoot )
+{
+ if ( !Ivy_ObjIsLatch(pLatch) && !Ivy_ObjIsBuf(pLatch) )
+ return 0;
+ if ( pLatch == pLatchRoot )
+ return 1;
+ return Ivy_ManLatchIsSelfFeed_rec( Ivy_ObjFanin0(pLatch), pLatchRoot );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Checks if latches form self-loop.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManLatchIsSelfFeed( Ivy_Obj_t * pLatch )
+{
+ if ( !Ivy_ObjIsLatch(pLatch) )
+ return 0;
+ return Ivy_ManLatchIsSelfFeed_rec( Ivy_ObjFanin0(pLatch), pLatch );
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns the number of dangling nodes removed.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManPropagateBuffers( Ivy_Man_t * p, int fUpdateLevel )
+{
+ Ivy_Obj_t * pNode;
+ int LimitFactor = 100;
+ int NodeBeg = Ivy_ManNodeNum(p);
+ int nSteps;
+ for ( nSteps = 0; Vec_PtrSize(p->vBufs) > 0; nSteps++ )
+ {
+ pNode = Vec_PtrEntryLast(p->vBufs);
+ while ( Ivy_ObjIsBuf(pNode) )
+ pNode = Ivy_ObjReadFirstFanout( p, pNode );
+ // check if this buffer should remain
+ if ( Ivy_ManLatchIsSelfFeed(pNode) )
+ {
+ Vec_PtrPop(p->vBufs);
+ continue;
+ }
+//printf( "Propagating buffer %d with input %d and output %d\n", Ivy_ObjFaninId0(pNode), Ivy_ObjFaninId0(Ivy_ObjFanin0(pNode)), pNode->Id );
+//printf( "Latch num %d\n", Ivy_ManLatchNum(p) );
+ Ivy_NodeFixBufferFanins( p, pNode, fUpdateLevel );
+ if ( nSteps > NodeBeg * LimitFactor )
+ {
+ printf( "Structural hashing is not finished after %d forward latch moves.\n", NodeBeg * LimitFactor );
+ printf( "This circuit cannot be forward-retimed completely. Quitting.\n" );
+ break;
+ }
+ }
+// printf( "Number of steps = %d. Nodes beg = %d. Nodes end = %d.\n", nSteps, NodeBeg, Ivy_ManNodeNum(p) );
+ return nSteps;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the AIG manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManPrintStats( Ivy_Man_t * p )
+{
+ printf( "PI/PO = %d/%d ", Ivy_ManPiNum(p), Ivy_ManPoNum(p) );
+ printf( "A = %7d. ", Ivy_ManAndNum(p) );
+ printf( "L = %5d. ", Ivy_ManLatchNum(p) );
+// printf( "X = %d. ", Ivy_ManExorNum(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 = %3d. ", Ivy_ManLatchNum(p)? -1 : Ivy_ManLevels(p) );
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Converts a combinational AIG manager into a sequential one.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManMakeSeq( Ivy_Man_t * p, int nLatches, int * pInits )
+{
+ Ivy_Obj_t * pObj, * pLatch;
+ Ivy_Init_t Init;
+ int i;
+ if ( nLatches == 0 )
+ return;
+ assert( nLatches < Ivy_ManPiNum(p) && nLatches < Ivy_ManPoNum(p) );
+ assert( Ivy_ManPiNum(p) == Vec_PtrSize(p->vPis) );
+ assert( Ivy_ManPoNum(p) == Vec_PtrSize(p->vPos) );
+ assert( Vec_PtrSize( p->vBufs ) == 0 );
+ // create fanouts
+ if ( p->fFanout == 0 )
+ Ivy_ManStartFanout( p );
+ // collect the POs to be converted into latches
+ for ( i = 0; i < nLatches; i++ )
+ {
+ // get the latch value
+ Init = pInits? pInits[i] : IVY_INIT_0;
+ // create latch
+ pObj = Ivy_ManPo( p, Ivy_ManPoNum(p) - nLatches + i );
+ pLatch = Ivy_Latch( p, Ivy_ObjChild0(pObj), Init );
+ Ivy_ObjDisconnect( p, pObj );
+ // recycle the old PO object
+ Vec_PtrWriteEntry( p->vObjs, pObj->Id, NULL );
+ Ivy_ManRecycleMemory( p, pObj );
+ // convert the corresponding PI to a buffer and connect it to the latch
+ pObj = Ivy_ManPi( p, Ivy_ManPiNum(p) - nLatches + i );
+ pObj->Type = IVY_BUF;
+ Ivy_ObjConnect( p, pObj, pLatch, NULL );
+ // save the buffer
+ Vec_PtrPush( p->vBufs, pObj );
+ }
+ // shrink the arrays
+ Vec_PtrShrink( p->vPis, Ivy_ManPiNum(p) - nLatches );
+ Vec_PtrShrink( p->vPos, Ivy_ManPoNum(p) - nLatches );
+ // update the counters of different objects
+ p->nObjs[IVY_PI] -= nLatches;
+ p->nObjs[IVY_PO] -= nLatches;
+ p->nObjs[IVY_BUF] += nLatches;
+ p->nDeleted -= 2 * nLatches;
+ // remove dangling nodes
+ Ivy_ManCleanup(p);
+ Ivy_ManCleanupSeq(p);
+/*
+ // check for dangling nodes
+ Ivy_ManForEachObj( p, pObj, i )
+ if ( !Ivy_ObjIsPi(pObj) && !Ivy_ObjIsPo(pObj) && !Ivy_ObjIsConst1(pObj) )
+ {
+ assert( Ivy_ObjRefs(pObj) > 0 );
+ assert( Ivy_ObjRefs(pObj) == Ivy_ObjFanoutNum(p, pObj) );
+ }
+*/
+ // perform hashing by propagating the buffers
+ Ivy_ManPropagateBuffers( p, 0 );
+ if ( Ivy_ManBufNum(p) )
+ printf( "The number of remaining buffers is %d.\n", Ivy_ManBufNum(p) );
+ // fix the levels
+ Ivy_ManResetLevels( p );
+ // check the resulting network
+ if ( !Ivy_ManCheck(p) )
+ printf( "Ivy_ManMakeSeq(): The check has failed.\n" );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyMem.c b/src/aig/ivy/ivyMem.c
new file mode 100644
index 00000000..2a96857c
--- /dev/null
+++ b/src/aig/ivy/ivyMem.c
@@ -0,0 +1,116 @@
+/**CFile****************************************************************
+
+ FileName [ivyMem.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Memory management for the AIG nodes.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyMem.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// memory management
+#define IVY_PAGE_SIZE 12 // page size containing 2^IVY_PAGE_SIZE nodes
+#define IVY_PAGE_MASK 4095 // page bitmask (2^IVY_PAGE_SIZE)-1
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Starts the internal memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManStartMemory( Ivy_Man_t * p )
+{
+ p->vChunks = Vec_PtrAlloc( 128 );
+ p->vPages = Vec_PtrAlloc( 128 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Stops the internal memory manager.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManStopMemory( Ivy_Man_t * p )
+{
+ void * pMemory;
+ int i;
+ Vec_PtrForEachEntry( p->vChunks, pMemory, i )
+ free( pMemory );
+ Vec_PtrFree( p->vChunks );
+ Vec_PtrFree( p->vPages );
+ p->pListFree = NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Allocates additional memory for the nodes.]
+
+ Description [Allocates IVY_PAGE_SIZE nodes. Aligns memory by 32 bytes.
+ Records the pointer to the AIG manager in the -1 entry.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManAddMemory( Ivy_Man_t * p )
+{
+ char * pMemory;
+ int i, nBytes;
+ int EntrySizeMax = 128;
+ assert( sizeof(Ivy_Obj_t) <= EntrySizeMax );
+ assert( p->pListFree == NULL );
+// assert( (Ivy_ManObjNum(p) & IVY_PAGE_MASK) == 0 );
+ // allocate new memory page
+ nBytes = sizeof(Ivy_Obj_t) * (1<<IVY_PAGE_SIZE) + EntrySizeMax;
+ pMemory = ALLOC( char, nBytes );
+ Vec_PtrPush( p->vChunks, pMemory );
+ // align memory at the 32-byte boundary
+ pMemory = pMemory + EntrySizeMax - (((int)pMemory) & (EntrySizeMax-1));
+ // remember the manager in the first entry
+ Vec_PtrPush( p->vPages, pMemory );
+ // break the memory down into nodes
+ p->pListFree = (Ivy_Obj_t *)pMemory;
+ for ( i = 1; i <= IVY_PAGE_MASK; i++ )
+ {
+ *((char **)pMemory) = pMemory + sizeof(Ivy_Obj_t);
+ pMemory += sizeof(Ivy_Obj_t);
+ }
+ *((char **)pMemory) = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyMulti.c b/src/aig/ivy/ivyMulti.c
new file mode 100644
index 00000000..a7970156
--- /dev/null
+++ b/src/aig/ivy/ivyMulti.c
@@ -0,0 +1,301 @@
+/**CFile****************************************************************
+
+ FileName [ivyMulti.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Constructing multi-input AND/EXOR gates.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyMulti.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+#define IVY_EVAL_LIMIT 128
+
+typedef struct Ivy_Eva_t_ Ivy_Eva_t;
+struct Ivy_Eva_t_
+{
+ Ivy_Obj_t * pArg; // the argument node
+ unsigned Mask; // the mask of covered nodes
+ int Weight; // the number of covered nodes
+};
+
+static void Ivy_MultiPrint( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals );
+static int Ivy_MultiCover( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals, int nLimit, Vec_Ptr_t * vSols );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Constructs a balanced tree while taking sharing into account.]
+
+ Description [Returns 1 if the implementation exists.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_MultiPlus( Ivy_Man_t * p, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Ivy_Type_t Type, int nLimit, Vec_Ptr_t * vSols )
+{
+ static Ivy_Eva_t pEvals[IVY_EVAL_LIMIT];
+ Ivy_Eva_t * pEval, * pFan0, * pFan1;
+ Ivy_Obj_t * pObj, * pTemp;
+ int nEvals, nEvalsOld, i, k, x, nLeaves;
+ unsigned uMaskAll;
+
+ // consider special cases
+ nLeaves = Vec_PtrSize(vLeaves);
+ assert( nLeaves > 2 );
+ if ( nLeaves > 32 || nLeaves + Vec_PtrSize(vCone) > IVY_EVAL_LIMIT )
+ return 0;
+// if ( nLeaves == 1 )
+// return Vec_PtrEntry( vLeaves, 0 );
+// if ( nLeaves == 2 )
+// return Ivy_Oper( Vec_PtrEntry(vLeaves, 0), Vec_PtrEntry(vLeaves, 1), Type );
+
+ // set the leaf entries
+ uMaskAll = ((1 << nLeaves) - 1);
+ nEvals = 0;
+ Vec_PtrForEachEntry( vLeaves, pObj, i )
+ {
+ pEval = pEvals + nEvals;
+ pEval->pArg = pObj;
+ pEval->Mask = (1 << nEvals);
+ pEval->Weight = 1;
+ // mark the leaf
+ Ivy_Regular(pObj)->TravId = nEvals;
+ nEvals++;
+ }
+
+ // propagate masks through the cone
+ Vec_PtrForEachEntry( vCone, pObj, i )
+ {
+ pObj->TravId = nEvals + i;
+ if ( Ivy_ObjIsBuf(pObj) )
+ pEvals[pObj->TravId].Mask = pEvals[Ivy_ObjFanin0(pObj)->TravId].Mask;
+ else
+ pEvals[pObj->TravId].Mask = pEvals[Ivy_ObjFanin0(pObj)->TravId].Mask | pEvals[Ivy_ObjFanin1(pObj)->TravId].Mask;
+ }
+
+ // set the internal entries
+ Vec_PtrForEachEntry( vCone, pObj, i )
+ {
+ if ( i == Vec_PtrSize(vCone) - 1 )
+ break;
+ // skip buffers
+ if ( Ivy_ObjIsBuf(pObj) )
+ continue;
+ // skip nodes without external fanout
+ if ( Ivy_ObjRefs(pObj) == 0 )
+ continue;
+ assert( !Ivy_IsComplement(pObj) );
+ pEval = pEvals + nEvals;
+ pEval->pArg = pObj;
+ pEval->Mask = pEvals[pObj->TravId].Mask;
+ pEval->Weight = Extra_WordCountOnes(pEval->Mask);
+ // mark the node
+ pObj->TravId = nEvals;
+ nEvals++;
+ }
+
+ // find the available nodes
+ nEvalsOld = nEvals;
+ for ( i = 1; i < nEvals; i++ )
+ for ( k = 0; k < i; k++ )
+ {
+ pFan0 = pEvals + i;
+ pFan1 = pEvals + k;
+ pTemp = Ivy_TableLookup(p, Ivy_ObjCreateGhost(p, pFan0->pArg, pFan1->pArg, Type, IVY_INIT_NONE));
+ // skip nodes in the cone
+ if ( pTemp == NULL || pTemp->fMarkB )
+ continue;
+ // skip the leaves
+ for ( x = 0; x < nLeaves; x++ )
+ if ( pTemp == Ivy_Regular(vLeaves->pArray[x]) )
+ break;
+ if ( x < nLeaves )
+ continue;
+ pEval = pEvals + nEvals;
+ pEval->pArg = pTemp;
+ pEval->Mask = pFan0->Mask | pFan1->Mask;
+ pEval->Weight = (pFan0->Mask & pFan1->Mask) ? Extra_WordCountOnes(pEval->Mask) : pFan0->Weight + pFan1->Weight;
+ // save the argument
+ pObj->TravId = nEvals;
+ nEvals++;
+ // quit if the number of entries exceeded the limit
+ if ( nEvals == IVY_EVAL_LIMIT )
+ goto Outside;
+ // quit if we found an acceptable implementation
+ if ( pEval->Mask == uMaskAll )
+ goto Outside;
+ }
+Outside:
+
+// Ivy_MultiPrint( pEvals, nLeaves, nEvals );
+ if ( !Ivy_MultiCover( p, pEvals, nLeaves, nEvals, nLimit, vSols ) )
+ return 0;
+ assert( Vec_PtrSize( vSols ) > 0 );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes how many uncovered ones this one covers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_MultiPrint( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals )
+{
+ Ivy_Eva_t * pEval;
+ int i, k;
+ for ( i = nLeaves; i < nEvals; i++ )
+ {
+ pEval = pEvals + i;
+ printf( "%2d (id = %5d) : |", i-nLeaves, Ivy_ObjId(pEval->pArg) );
+ for ( k = 0; k < nLeaves; k++ )
+ {
+ if ( pEval->Mask & (1 << k) )
+ printf( "+" );
+ else
+ printf( " " );
+ }
+ printf( "| Lev = %d.\n", Ivy_ObjLevel(pEval->pArg) );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes how many uncovered ones this one covers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_MultiWeight( unsigned uMask, int nMaskOnes, unsigned uFound )
+{
+ assert( uMask & ~uFound );
+ if ( (uMask & uFound) == 0 )
+ return nMaskOnes;
+ return Extra_WordCountOnes( uMask & ~uFound );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Finds the cover.]
+
+ Description [Returns 1 if the cover is found.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_MultiCover( Ivy_Man_t * p, Ivy_Eva_t * pEvals, int nLeaves, int nEvals, int nLimit, Vec_Ptr_t * vSols )
+{
+ int fVerbose = 0;
+ Ivy_Eva_t * pEval, * pEvalBest;
+ unsigned uMaskAll, uFound, uTemp;
+ int i, k, BestK, WeightBest, WeightCur, LevelBest, LevelCur;
+ uMaskAll = (nLeaves == 32)? (~(unsigned)0) : ((1 << nLeaves) - 1);
+ uFound = 0;
+ // solve the covering problem
+ if ( fVerbose )
+ printf( "Solution: " );
+ Vec_PtrClear( vSols );
+ for ( i = 0; i < nLimit; i++ )
+ {
+ BestK = -1;
+ for ( k = nEvals - 1; k >= 0; k-- )
+ {
+ pEval = pEvals + k;
+ if ( (pEval->Mask & ~uFound) == 0 )
+ continue;
+ if ( BestK == -1 )
+ {
+ BestK = k;
+ pEvalBest = pEval;
+ WeightBest = Ivy_MultiWeight( pEvalBest->Mask, pEvalBest->Weight, uFound );
+ LevelBest = Ivy_ObjLevel( Ivy_Regular(pEvalBest->pArg) );
+ continue;
+ }
+ // compare BestK and the new one (k)
+ WeightCur = Ivy_MultiWeight( pEval->Mask, pEval->Weight, uFound );
+ LevelCur = Ivy_ObjLevel( Ivy_Regular(pEval->pArg) );
+ if ( WeightBest < WeightCur ||
+ (WeightBest == WeightCur && LevelBest > LevelCur) )
+ {
+ BestK = k;
+ pEvalBest = pEval;
+ WeightBest = WeightCur;
+ LevelBest = LevelCur;
+ }
+ }
+ assert( BestK != -1 );
+ // if the cost is only 1, take the leaf
+ if ( WeightBest == 1 && BestK >= nLeaves )
+ {
+ uTemp = (pEvalBest->Mask & ~uFound);
+ for ( k = 0; k < nLeaves; k++ )
+ if ( uTemp & (1 << k) )
+ break;
+ assert( k < nLeaves );
+ BestK = k;
+ pEvalBest = pEvals + BestK;
+ }
+ if ( fVerbose )
+ {
+ if ( BestK < nLeaves )
+ printf( "L(%d) ", BestK );
+ else
+ printf( "%d ", BestK - nLeaves );
+ }
+ // update the found set
+ Vec_PtrPush( vSols, pEvalBest->pArg );
+ uFound |= pEvalBest->Mask;
+ if ( uFound == uMaskAll )
+ break;
+ }
+ if ( uFound == uMaskAll )
+ {
+ if ( fVerbose )
+ printf( " Found \n\n" );
+ return 1;
+ }
+ else
+ {
+ if ( fVerbose )
+ printf( " Not found \n\n" );
+ return 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyMulti8.c b/src/aig/ivy/ivyMulti8.c
new file mode 100644
index 00000000..059d1500
--- /dev/null
+++ b/src/aig/ivy/ivyMulti8.c
@@ -0,0 +1,427 @@
+/**CFile****************************************************************
+
+ FileName [ivyMulti.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Constructing multi-input AND/EXOR gates.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyMulti.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+typedef struct Ivy_Eval_t_ Ivy_Eval_t;
+struct Ivy_Eval_t_
+{
+ unsigned Mask : 5; // the mask of covered nodes
+ unsigned Weight : 3; // the number of covered nodes
+ unsigned Cost : 4; // the number of overlapping nodes
+ unsigned Level : 12; // the level of this node
+ unsigned Fan0 : 4; // the first fanin
+ unsigned Fan1 : 4; // the second fanin
+};
+
+static Ivy_Obj_t * Ivy_MultiBuild_rec( Ivy_Eval_t * pEvals, int iNum, Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type );
+static void Ivy_MultiSort( Ivy_Obj_t ** pArgs, int nArgs );
+static int Ivy_MultiPushUniqueOrderByLevel( Ivy_Obj_t ** pArray, int nArgs, Ivy_Obj_t * pNode );
+static Ivy_Obj_t * Ivy_MultiEval( Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type );
+
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Constructs the well-balanced tree of gates.]
+
+ Description [Disregards levels and possible logic sharing.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Multi_rec( Ivy_Obj_t ** ppObjs, int nObjs, Ivy_Type_t Type )
+{
+ Ivy_Obj_t * pObj1, * pObj2;
+ if ( nObjs == 1 )
+ return ppObjs[0];
+ pObj1 = Ivy_Multi_rec( ppObjs, nObjs/2, Type );
+ pObj2 = Ivy_Multi_rec( ppObjs + nObjs/2, nObjs - nObjs/2, Type );
+ return Ivy_Oper( pObj1, pObj2, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs a balanced tree while taking sharing into account.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Multi( Ivy_Obj_t ** pArgsInit, int nArgs, Ivy_Type_t Type )
+{
+ static char NumBits[32] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5};
+ static Ivy_Eval_t pEvals[15+15*14/2];
+ static Ivy_Obj_t * pArgs[16];
+ Ivy_Eval_t * pEva, * pEvaBest;
+ int nArgsNew, nEvals, i, k;
+ Ivy_Obj_t * pTemp;
+
+ // consider the case of one argument
+ assert( nArgs > 0 );
+ if ( nArgs == 1 )
+ return pArgsInit[0];
+ // consider the case of two arguments
+ if ( nArgs == 2 )
+ return Ivy_Oper( pArgsInit[0], pArgsInit[1], Type );
+
+//Ivy_MultiEval( pArgsInit, nArgs, Type ); printf( "\n" );
+
+ // set the initial ones
+ for ( i = 0; i < nArgs; i++ )
+ {
+ pArgs[i] = pArgsInit[i];
+ pEva = pEvals + i;
+ pEva->Mask = (1 << i);
+ pEva->Weight = 1;
+ pEva->Cost = 0;
+ pEva->Level = Ivy_Regular(pArgs[i])->Level;
+ pEva->Fan0 = 0;
+ pEva->Fan1 = 0;
+ }
+
+ // find the available nodes
+ pEvaBest = pEvals;
+ nArgsNew = nArgs;
+ for ( i = 1; i < nArgsNew; i++ )
+ for ( k = 0; k < i; k++ )
+ if ( pTemp = Ivy_TableLookup(Ivy_ObjCreateGhost(pArgs[k], pArgs[i], Type, IVY_INIT_NONE)) )
+ {
+ pEva = pEvals + nArgsNew;
+ pEva->Mask = pEvals[k].Mask | pEvals[i].Mask;
+ pEva->Weight = NumBits[pEva->Mask];
+ pEva->Cost = pEvals[k].Cost + pEvals[i].Cost + NumBits[pEvals[k].Mask & pEvals[i].Mask];
+ pEva->Level = 1 + IVY_MAX(pEvals[k].Level, pEvals[i].Level);
+ pEva->Fan0 = k;
+ pEva->Fan1 = i;
+// assert( pEva->Level == (unsigned)Ivy_ObjLevel(pTemp) );
+ // compare
+ if ( pEvaBest->Weight < pEva->Weight ||
+ pEvaBest->Weight == pEva->Weight && pEvaBest->Cost > pEva->Cost ||
+ pEvaBest->Weight == pEva->Weight && pEvaBest->Cost == pEva->Cost && pEvaBest->Level > pEva->Level )
+ pEvaBest = pEva;
+ // save the argument
+ pArgs[nArgsNew++] = pTemp;
+ if ( nArgsNew == 15 )
+ goto Outside;
+ }
+Outside:
+
+// printf( "Best = %d.\n", pEvaBest - pEvals );
+
+ // the case of no common nodes
+ if ( nArgsNew == nArgs )
+ {
+ Ivy_MultiSort( pArgs, nArgs );
+ return Ivy_MultiBalance_rec( pArgs, nArgs, Type );
+ }
+ // the case of one common node
+ if ( nArgsNew == nArgs + 1 )
+ {
+ assert( pEvaBest - pEvals == nArgs );
+ k = 0;
+ for ( i = 0; i < nArgs; i++ )
+ if ( i != (int)pEvaBest->Fan0 && i != (int)pEvaBest->Fan1 )
+ pArgs[k++] = pArgs[i];
+ pArgs[k++] = pArgs[nArgs];
+ assert( k == nArgs - 1 );
+ nArgs = k;
+ Ivy_MultiSort( pArgs, nArgs );
+ return Ivy_MultiBalance_rec( pArgs, nArgs, Type );
+ }
+ // the case when there is a node that covers everything
+ if ( (int)pEvaBest->Mask == ((1 << nArgs) - 1) )
+ return Ivy_MultiBuild_rec( pEvals, pEvaBest - pEvals, pArgs, nArgsNew, Type );
+
+ // evaluate node pairs
+ nEvals = nArgsNew;
+ for ( i = 1; i < nArgsNew; i++ )
+ for ( k = 0; k < i; k++ )
+ {
+ pEva = pEvals + nEvals;
+ pEva->Mask = pEvals[k].Mask | pEvals[i].Mask;
+ pEva->Weight = NumBits[pEva->Mask];
+ pEva->Cost = pEvals[k].Cost + pEvals[i].Cost + NumBits[pEvals[k].Mask & pEvals[i].Mask];
+ pEva->Level = 1 + IVY_MAX(pEvals[k].Level, pEvals[i].Level);
+ pEva->Fan0 = k;
+ pEva->Fan1 = i;
+ // compare
+ if ( pEvaBest->Weight < pEva->Weight ||
+ pEvaBest->Weight == pEva->Weight && pEvaBest->Cost > pEva->Cost ||
+ pEvaBest->Weight == pEva->Weight && pEvaBest->Cost == pEva->Cost && pEvaBest->Level > pEva->Level )
+ pEvaBest = pEva;
+ // save the argument
+ nEvals++;
+ }
+ assert( pEvaBest - pEvals >= nArgsNew );
+
+// printf( "Used (%d, %d).\n", pEvaBest->Fan0, pEvaBest->Fan1 );
+
+ // get the best implementation
+ pTemp = Ivy_MultiBuild_rec( pEvals, pEvaBest - pEvals, pArgs, nArgsNew, Type );
+
+ // collect those not covered by EvaBest
+ k = 0;
+ for ( i = 0; i < nArgs; i++ )
+ if ( (pEvaBest->Mask & (1 << i)) == 0 )
+ pArgs[k++] = pArgs[i];
+ pArgs[k++] = pTemp;
+ assert( k == nArgs - (int)pEvaBest->Weight + 1 );
+ nArgs = k;
+ Ivy_MultiSort( pArgs, nArgs );
+ return Ivy_MultiBalance_rec( pArgs, nArgs, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements multi-input AND/EXOR operation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_MultiBuild_rec( Ivy_Eval_t * pEvals, int iNum, Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type )
+{
+ Ivy_Obj_t * pNode0, * pNode1;
+ if ( iNum < nArgs )
+ return pArgs[iNum];
+ pNode0 = Ivy_MultiBuild_rec( pEvals, pEvals[iNum].Fan0, pArgs, nArgs, Type );
+ pNode1 = Ivy_MultiBuild_rec( pEvals, pEvals[iNum].Fan1, pArgs, nArgs, Type );
+ return Ivy_Oper( pNode0, pNode1, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Selection-sorts the nodes in the decreasing over of level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_MultiSort( Ivy_Obj_t ** pArgs, int nArgs )
+{
+ Ivy_Obj_t * pTemp;
+ int i, j, iBest;
+
+ for ( i = 0; i < nArgs-1; i++ )
+ {
+ iBest = i;
+ for ( j = i+1; j < nArgs; j++ )
+ if ( Ivy_Regular(pArgs[j])->Level > Ivy_Regular(pArgs[iBest])->Level )
+ iBest = j;
+ pTemp = pArgs[i];
+ pArgs[i] = pArgs[iBest];
+ pArgs[iBest] = pTemp;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Inserts a new node in the order by levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_MultiPushUniqueOrderByLevel( Ivy_Obj_t ** pArray, int nArgs, Ivy_Obj_t * pNode )
+{
+ Ivy_Obj_t * pNode1, * pNode2;
+ int i;
+ // try to find the node in the array
+ for ( i = 0; i < nArgs; i++ )
+ if ( pArray[i] == pNode )
+ return nArgs;
+ // put the node last
+ pArray[nArgs++] = pNode;
+ // find the place to put the new node
+ for ( i = nArgs-1; i > 0; i-- )
+ {
+ pNode1 = pArray[i ];
+ pNode2 = pArray[i-1];
+ if ( Ivy_Regular(pNode1)->Level <= Ivy_Regular(pNode2)->Level )
+ break;
+ pArray[i ] = pNode2;
+ pArray[i-1] = pNode1;
+ }
+ return nArgs;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Balances the array recursively.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_MultiBalance_rec( Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type )
+{
+ Ivy_Obj_t * pNodeNew;
+ // consider the case of one argument
+ assert( nArgs > 0 );
+ if ( nArgs == 1 )
+ return pArgs[0];
+ // consider the case of two arguments
+ if ( nArgs == 2 )
+ return Ivy_Oper( pArgs[0], pArgs[1], Type );
+ // get the last two nodes
+ pNodeNew = Ivy_Oper( pArgs[nArgs-1], pArgs[nArgs-2], Type );
+ // add the new node
+ nArgs = Ivy_MultiPushUniqueOrderByLevel( pArgs, nArgs - 2, pNodeNew );
+ return Ivy_MultiBalance_rec( pArgs, nArgs, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements multi-input AND/EXOR operation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_MultiEval( Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type )
+{
+ Ivy_Obj_t * pTemp;
+ int i, k;
+ int nArgsOld = nArgs;
+ for ( i = 0; i < nArgs; i++ )
+ printf( "%d[%d] ", i, Ivy_Regular(pArgs[i])->Level );
+ for ( i = 1; i < nArgs; i++ )
+ for ( k = 0; k < i; k++ )
+ {
+ pTemp = Ivy_TableLookup(Ivy_ObjCreateGhost(pArgs[k], pArgs[i], Type, IVY_INIT_NONE));
+ if ( pTemp != NULL )
+ {
+ printf( "%d[%d]=(%d,%d) ", nArgs, Ivy_Regular(pTemp)->Level, k, i );
+ pArgs[nArgs++] = pTemp;
+ }
+ }
+ printf( " ((%d/%d)) ", nArgsOld, nArgs-nArgsOld );
+ return NULL;
+}
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Old code.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Multi1( Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type )
+{
+ Ivy_Obj_t * pArgsRef[5], * pTemp;
+ int i, k, m, nArgsNew, Counter = 0;
+
+
+//Ivy_MultiEval( pArgs, nArgs, Type ); printf( "\n" );
+
+
+ assert( Type == IVY_AND || Type == IVY_EXOR );
+ assert( nArgs > 0 );
+ if ( nArgs == 1 )
+ return pArgs[0];
+
+ // find the nodes with more than one fanout
+ nArgsNew = 0;
+ for ( i = 0; i < nArgs; i++ )
+ if ( Ivy_ObjRefs( Ivy_Regular(pArgs[i]) ) > 0 )
+ pArgsRef[nArgsNew++] = pArgs[i];
+
+ // go through pairs
+ if ( nArgsNew >= 2 )
+ for ( i = 0; i < nArgsNew; i++ )
+ for ( k = i + 1; k < nArgsNew; k++ )
+ if ( pTemp = Ivy_TableLookup(Ivy_ObjCreateGhost(pArgsRef[i], pArgsRef[k], Type, IVY_INIT_NONE)) )
+ Counter++;
+// printf( "%d", Counter );
+
+ // go through pairs
+ if ( nArgsNew >= 2 )
+ for ( i = 0; i < nArgsNew; i++ )
+ for ( k = i + 1; k < nArgsNew; k++ )
+ if ( pTemp = Ivy_TableLookup(Ivy_ObjCreateGhost(pArgsRef[i], pArgsRef[k], Type, IVY_INIT_NONE)) )
+ {
+ nArgsNew = 0;
+ for ( m = 0; m < nArgs; m++ )
+ if ( pArgs[m] != pArgsRef[i] && pArgs[m] != pArgsRef[k] )
+ pArgs[nArgsNew++] = pArgs[m];
+ pArgs[nArgsNew++] = pTemp;
+ assert( nArgsNew == nArgs - 1 );
+ return Ivy_Multi1( pArgs, nArgsNew, Type );
+ }
+ return Ivy_Multi_rec( pArgs, nArgs, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Old code.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Multi2( Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type )
+{
+ assert( Type == IVY_AND || Type == IVY_EXOR );
+ assert( nArgs > 0 );
+ return Ivy_Multi_rec( pArgs, nArgs, Type );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyObj.c b/src/aig/ivy/ivyObj.c
new file mode 100644
index 00000000..59dda19c
--- /dev/null
+++ b/src/aig/ivy/ivyObj.c
@@ -0,0 +1,476 @@
+/**CFile****************************************************************
+
+ FileName [ivyObj.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Adding/removing objects.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyObj.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node assuming it does not exist.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ObjCreatePi( Ivy_Man_t * p )
+{
+ return Ivy_ObjCreate( p, Ivy_ObjCreateGhost(p, NULL, NULL, IVY_PI, IVY_INIT_NONE) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node assuming it does not exist.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ObjCreatePo( Ivy_Man_t * p, Ivy_Obj_t * pDriver )
+{
+ return Ivy_ObjCreate( p, Ivy_ObjCreateGhost(p, pDriver, NULL, IVY_PO, IVY_INIT_NONE) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Create the new node assuming it does not exist.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ObjCreate( Ivy_Man_t * p, Ivy_Obj_t * pGhost )
+{
+ Ivy_Obj_t * pObj;
+ assert( !Ivy_IsComplement(pGhost) );
+ assert( Ivy_ObjIsGhost(pGhost) );
+ assert( Ivy_TableLookup(p, pGhost) == NULL );
+ // get memory for the new object
+ pObj = Ivy_ManFetchMemory( p );
+ assert( Ivy_ObjIsNone(pObj) );
+ pObj->Id = Vec_PtrSize(p->vObjs);
+ Vec_PtrPush( p->vObjs, pObj );
+ // add basic info (fanins, compls, type, init)
+ pObj->Type = pGhost->Type;
+ pObj->Init = pGhost->Init;
+ // add connections
+ Ivy_ObjConnect( p, pObj, pGhost->pFanin0, pGhost->pFanin1 );
+ // compute level
+ if ( Ivy_ObjIsNode(pObj) )
+ pObj->Level = Ivy_ObjLevelNew(pObj);
+ else if ( Ivy_ObjIsLatch(pObj) )
+ pObj->Level = 0;
+ else if ( Ivy_ObjIsOneFanin(pObj) )
+ pObj->Level = Ivy_ObjFanin0(pObj)->Level;
+ else if ( !Ivy_ObjIsPi(pObj) )
+ assert( 0 );
+ // create phase
+ if ( Ivy_ObjIsNode(pObj) )
+ pObj->fPhase = Ivy_ObjFaninPhase(Ivy_ObjChild0(pObj)) & Ivy_ObjFaninPhase(Ivy_ObjChild1(pObj));
+ else if ( Ivy_ObjIsOneFanin(pObj) )
+ pObj->fPhase = Ivy_ObjFaninPhase(Ivy_ObjChild0(pObj));
+ // set the fail TFO flag
+ if ( Ivy_ObjIsNode(pObj) )
+ pObj->fFailTfo = Ivy_ObjFanin0(pObj)->fFailTfo | Ivy_ObjFanin1(pObj)->fFailTfo;
+ // mark the fanins in a special way if the node is EXOR
+ if ( Ivy_ObjIsExor(pObj) )
+ {
+ Ivy_ObjFanin0(pObj)->fExFan = 1;
+ Ivy_ObjFanin1(pObj)->fExFan = 1;
+ }
+ // add PIs/POs to the arrays
+ if ( Ivy_ObjIsPi(pObj) )
+ Vec_PtrPush( p->vPis, pObj );
+ else if ( Ivy_ObjIsPo(pObj) )
+ Vec_PtrPush( p->vPos, pObj );
+// else if ( Ivy_ObjIsBuf(pObj) )
+// Vec_PtrPush( p->vBufs, pObj );
+ if ( p->vRequired && Vec_IntSize(p->vRequired) <= pObj->Id )
+ Vec_IntFillExtra( p->vRequired, 2 * Vec_IntSize(p->vRequired), 1000000 );
+ // update node counters of the manager
+ p->nObjs[Ivy_ObjType(pObj)]++;
+ p->nCreated++;
+
+// printf( "Adding %sAIG node: ", p->pHaig==NULL? "H":" " );
+// Ivy_ObjPrintVerbose( p, pObj, p->pHaig==NULL );
+// printf( "\n" );
+
+ // if HAIG is defined, create a corresponding node
+ if ( p->pHaig )
+ Ivy_ManHaigCreateObj( p, pObj );
+ return pObj;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Connect the object to the fanin.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjConnect( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFan0, Ivy_Obj_t * pFan1 )
+{
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjIsPi(pObj) || Ivy_ObjIsOneFanin(pObj) || pFan1 != NULL );
+ // add the first fanin
+ pObj->pFanin0 = pFan0;
+ pObj->pFanin1 = pFan1;
+ // increment references of the fanins and add their fanouts
+ if ( Ivy_ObjFanin0(pObj) != NULL )
+ {
+ Ivy_ObjRefsInc( Ivy_ObjFanin0(pObj) );
+ if ( p->fFanout )
+ Ivy_ObjAddFanout( p, Ivy_ObjFanin0(pObj), pObj );
+ }
+ if ( Ivy_ObjFanin1(pObj) != NULL )
+ {
+ Ivy_ObjRefsInc( Ivy_ObjFanin1(pObj) );
+ if ( p->fFanout )
+ Ivy_ObjAddFanout( p, Ivy_ObjFanin1(pObj), pObj );
+ }
+ // add the node to the structural hash table
+ Ivy_TableInsert( p, pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Connect the object to the fanin.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+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 ( pObj->pFanin0 != NULL )
+ {
+ Ivy_ObjRefsDec(Ivy_ObjFanin0(pObj));
+ if ( p->fFanout )
+ Ivy_ObjDeleteFanout( p, Ivy_ObjFanin0(pObj), pObj );
+ }
+ if ( pObj->pFanin1 != NULL )
+ {
+ Ivy_ObjRefsDec(Ivy_ObjFanin1(pObj));
+ 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;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces the first fanin of the node by the new fanin.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjPatchFanin0( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Obj_t * pFaninNew )
+{
+ Ivy_Obj_t * pFaninOld;
+ assert( !Ivy_IsComplement(pObj) );
+ pFaninOld = Ivy_ObjFanin0(pObj);
+ // decrement ref and remove fanout
+ Ivy_ObjRefsDec( pFaninOld );
+ if ( p->fFanout )
+ Ivy_ObjDeleteFanout( p, pFaninOld, 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_ObjIsConst1(pFaninOld) && Ivy_ObjRefs(pFaninOld) == 0 )
+ Ivy_ObjDelete_rec( p, pFaninOld, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjDelete( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fFreeTop )
+{
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjRefs(pObj) == 0 || !fFreeTop );
+ // update node counters of the manager
+ p->nObjs[pObj->Type]--;
+ p->nDeleted++;
+ // remove connections
+ Ivy_ObjDisconnect( p, pObj );
+ // remove PIs/POs from the arrays
+ if ( Ivy_ObjIsPi(pObj) )
+ Vec_PtrRemove( p->vPis, pObj );
+ else if ( Ivy_ObjIsPo(pObj) )
+ Vec_PtrRemove( p->vPos, pObj );
+ else if ( p->fFanout && Ivy_ObjIsBuf(pObj) )
+ Vec_PtrRemove( p->vBufs, pObj );
+ // clean and recycle the entry
+ if ( fFreeTop )
+ {
+ // free the node
+ Vec_PtrWriteEntry( p->vObjs, pObj->Id, NULL );
+ Ivy_ManRecycleMemory( p, pObj );
+ }
+ else
+ {
+ int nRefsOld = pObj->nRefs;
+ Ivy_Obj_t * pFanout = pObj->pFanout;
+ Ivy_ObjClean( pObj );
+ pObj->pFanout = pFanout;
+ pObj->nRefs = nRefsOld;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the MFFC of the node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjDelete_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fFreeTop )
+{
+ Ivy_Obj_t * pFanin0, * pFanin1;
+ assert( !Ivy_IsComplement(pObj) );
+ assert( !Ivy_ObjIsNone(pObj) );
+ if ( Ivy_ObjIsConst1(pObj) || Ivy_ObjIsPi(pObj) )
+ return;
+ pFanin0 = Ivy_ObjFanin0(pObj);
+ pFanin1 = Ivy_ObjFanin1(pObj);
+ Ivy_ObjDelete( p, pObj, fFreeTop );
+ if ( pFanin0 && !Ivy_ObjIsNone(pFanin0) && Ivy_ObjRefs(pFanin0) == 0 )
+ Ivy_ObjDelete_rec( p, pFanin0, 1 );
+ if ( pFanin1 && !Ivy_ObjIsNone(pFanin1) && Ivy_ObjRefs(pFanin1) == 0 )
+ Ivy_ObjDelete_rec( p, pFanin1, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces one object by another.]
+
+ Description [Both objects are currently in the manager. The new object
+ (pObjNew) should be used instead of the old object (pObjOld). If the
+ new object is complemented or used, the buffer is added.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjReplace( Ivy_Man_t * p, Ivy_Obj_t * pObjOld, Ivy_Obj_t * pObjNew, int fDeleteOld, int fFreeTop, int fUpdateLevel )
+{
+ int nRefsOld;//, clk;
+ // the object to be replaced cannot be complemented
+ assert( !Ivy_IsComplement(pObjOld) );
+ // the object to be replaced cannot be a terminal
+ assert( Ivy_ObjIsNone(pObjOld) || !Ivy_ObjIsPi(pObjOld) );
+ // the object to be used cannot be a PO or assert
+ assert( !Ivy_ObjIsBuf(Ivy_Regular(pObjNew)) );
+ // the object cannot be the same
+ assert( pObjOld != Ivy_Regular(pObjNew) );
+//printf( "Replacing %d by %d.\n", Ivy_Regular(pObjOld)->Id, Ivy_Regular(pObjNew)->Id );
+
+ // if HAIG is defined, create the choice node
+ if ( p->pHaig )
+ {
+// if ( pObjOld->Id == 31 )
+// {
+// Ivy_ManShow( p, 0 );
+// Ivy_ManShow( p->pHaig, 1 );
+// }
+ Ivy_ManHaigCreateChoice( p, pObjOld, pObjNew );
+ }
+ // if the new object is complemented or already used, add the buffer
+ if ( Ivy_IsComplement(pObjNew) || Ivy_ObjIsLatch(pObjNew) || Ivy_ObjRefs(pObjNew) > 0 || Ivy_ObjIsPi(pObjNew) || Ivy_ObjIsConst1(pObjNew) )
+ pObjNew = Ivy_ObjCreate( p, Ivy_ObjCreateGhost(p, pObjNew, NULL, IVY_BUF, IVY_INIT_NONE) );
+ assert( !Ivy_IsComplement(pObjNew) );
+ if ( fUpdateLevel )
+ {
+//clk = clock();
+ // if the new node's arrival time is different, recursively update arrival time of the fanouts
+ if ( p->fFanout && !Ivy_ObjIsBuf(pObjNew) && pObjOld->Level != pObjNew->Level )
+ {
+ assert( Ivy_ObjIsNode(pObjOld) );
+ pObjOld->Level = pObjNew->Level;
+ Ivy_ObjUpdateLevel_rec( p, pObjOld );
+ }
+//p->time1 += clock() - clk;
+ // if the new node's required time has changed, recursively update required time of the fanins
+//clk = clock();
+ if ( p->vRequired )
+ {
+ int ReqNew = Vec_IntEntry(p->vRequired, pObjOld->Id);
+ if ( ReqNew < Vec_IntEntry(p->vRequired, pObjNew->Id) )
+ {
+ Vec_IntWriteEntry( p->vRequired, pObjNew->Id, ReqNew );
+ Ivy_ObjUpdateLevelR_rec( p, pObjNew, ReqNew );
+ }
+ }
+//p->time2 += clock() - clk;
+ }
+ // delete the old object
+ if ( fDeleteOld )
+ Ivy_ObjDelete_rec( p, pObjOld, fFreeTop );
+ // 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->fFanout )
+ {
+ Ivy_ObjPatchFanout( p, Ivy_ObjFanin0(pObjOld), pObjNew, pObjOld );
+ if ( Ivy_ObjFanin1(pObjOld) )
+ Ivy_ObjPatchFanout( p, Ivy_ObjFanin1(pObjOld), pObjNew, pObjOld );
+ }
+ // update the hash table
+ Ivy_TableUpdate( p, pObjNew, pObjOld->Id );
+ // recycle the object that was taken over by pObjOld
+ Vec_PtrWriteEntry( p->vObjs, pObjNew->Id, NULL );
+ Ivy_ManRecycleMemory( p, pObjNew );
+ // if the new node is the buffer propagate it
+ if ( p->fFanout && Ivy_ObjIsBuf(pObjOld) )
+ Vec_PtrPush( p->vBufs, pObjOld );
+// Ivy_ManCheckFanouts( p );
+// printf( "\n" );
+/*
+ if ( p->pHaig )
+ {
+ int x;
+ Ivy_ManShow( p, 0, NULL );
+ Ivy_ManShow( p->pHaig, 1, NULL );
+ x = 0;
+ }
+*/
+// if ( Ivy_ManCheckFanoutNums(p) )
+// {
+// int x = 0;
+// }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Fixes buffer fanins.]
+
+ Description [This situation happens because NodeReplace is a lazy
+ procedure, which does not propagate the change to the fanouts but
+ instead records the change in the form of a buf/inv node.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_NodeFixBufferFanins( Ivy_Man_t * p, Ivy_Obj_t * pNode, int fUpdateLevel )
+{
+ Ivy_Obj_t * pFanReal0, * pFanReal1, * pResult;
+ if ( Ivy_ObjIsPo(pNode) )
+ {
+ if ( !Ivy_ObjIsBuf(Ivy_ObjFanin0(pNode)) )
+ 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)) )
+ return;
+ // get the real fanins
+ pFanReal0 = Ivy_ObjReal( Ivy_ObjChild0(pNode) );
+ pFanReal1 = Ivy_ObjReal( Ivy_ObjChild1(pNode) );
+ // get the new node
+ if ( Ivy_ObjIsNode(pNode) )
+ pResult = Ivy_Oper( p, pFanReal0, pFanReal1, Ivy_ObjType(pNode) );
+ else if ( Ivy_ObjIsLatch(pNode) )
+ pResult = Ivy_Latch( p, pFanReal0, Ivy_ObjInit(pNode) );
+ else
+ assert( 0 );
+
+//printf( "===== Replacing %d by %d.\n", pNode->Id, pResult->Id );
+//Ivy_ObjPrintVerbose( p, pNode, 0 ); printf( "\n" );
+//Ivy_ObjPrintVerbose( p, pResult, 0 ); printf( "\n" );
+
+ // perform the replacement
+ Ivy_ObjReplace( p, pNode, pResult, 1, 0, fUpdateLevel );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyOper.c b/src/aig/ivy/ivyOper.c
new file mode 100644
index 00000000..8115ce4f
--- /dev/null
+++ b/src/aig/ivy/ivyOper.c
@@ -0,0 +1,293 @@
+/**CFile****************************************************************
+
+ FileName [ivyOper.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [AIG operations.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyOper.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// procedure to detect an EXOR gate
+static inline int Ivy_ObjIsExorType( Ivy_Obj_t * p0, Ivy_Obj_t * p1, Ivy_Obj_t ** ppFan0, Ivy_Obj_t ** ppFan1 )
+{
+ if ( !Ivy_IsComplement(p0) || !Ivy_IsComplement(p1) )
+ return 0;
+ p0 = Ivy_Regular(p0);
+ p1 = Ivy_Regular(p1);
+ if ( !Ivy_ObjIsAnd(p0) || !Ivy_ObjIsAnd(p1) )
+ return 0;
+ if ( Ivy_ObjFanin0(p0) != Ivy_ObjFanin0(p1) || Ivy_ObjFanin1(p0) != Ivy_ObjFanin1(p1) )
+ return 0;
+ if ( Ivy_ObjFaninC0(p0) == Ivy_ObjFaninC0(p1) || Ivy_ObjFaninC1(p0) == Ivy_ObjFaninC1(p1) )
+ return 0;
+ *ppFan0 = Ivy_ObjChild0(p0);
+ *ppFan1 = Ivy_ObjChild1(p0);
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Perform one operation.]
+
+ Description [The argument nodes can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Oper( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1, Ivy_Type_t Type )
+{
+ if ( Type == IVY_AND )
+ return Ivy_And( p, p0, p1 );
+ if ( Type == IVY_EXOR )
+ return Ivy_Exor( p, p0, p1 );
+ assert( 0 );
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs canonicization step.]
+
+ Description [The argument nodes can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_And( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 )
+{
+// Ivy_Obj_t * pFan0, * pFan1;
+ // check trivial cases
+ if ( p0 == p1 )
+ return p0;
+ if ( p0 == Ivy_Not(p1) )
+ return Ivy_Not(p->pConst1);
+ if ( Ivy_Regular(p0) == p->pConst1 )
+ return p0 == p->pConst1 ? p1 : Ivy_Not(p->pConst1);
+ if ( Ivy_Regular(p1) == p->pConst1 )
+ return p1 == p->pConst1 ? p0 : Ivy_Not(p->pConst1);
+ // check if it can be an EXOR gate
+// if ( Ivy_ObjIsExorType( p0, p1, &pFan0, &pFan1 ) )
+// return Ivy_CanonExor( pFan0, pFan1 );
+ return Ivy_CanonAnd( p, p0, p1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs canonicization step.]
+
+ Description [The argument nodes can be complemented.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Exor( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 )
+{
+/*
+ // check trivial cases
+ if ( p0 == p1 )
+ return Ivy_Not(p->pConst1);
+ if ( p0 == Ivy_Not(p1) )
+ return p->pConst1;
+ if ( Ivy_Regular(p0) == p->pConst1 )
+ return Ivy_NotCond( p1, p0 == p->pConst1 );
+ if ( Ivy_Regular(p1) == p->pConst1 )
+ return Ivy_NotCond( p0, p1 == p->pConst1 );
+ // check the table
+ return Ivy_CanonExor( p, p0, p1 );
+*/
+ return Ivy_Or( p, Ivy_And(p, p0, Ivy_Not(p1)), Ivy_And(p, Ivy_Not(p0), p1) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements Boolean OR.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Or( Ivy_Man_t * p, Ivy_Obj_t * p0, Ivy_Obj_t * p1 )
+{
+ return Ivy_Not( Ivy_And( p, Ivy_Not(p0), Ivy_Not(p1) ) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements ITE operation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Mux( Ivy_Man_t * p, Ivy_Obj_t * pC, Ivy_Obj_t * p1, Ivy_Obj_t * p0 )
+{
+ Ivy_Obj_t * pTempA1, * pTempA2, * pTempB1, * pTempB2, * pTemp;
+ int Count0, Count1;
+ // consider trivial cases
+ if ( p0 == Ivy_Not(p1) )
+ return Ivy_Exor( p, pC, p0 );
+ // other cases can be added
+ // implement the first MUX (F = C * x1 + C' * x0)
+ pTempA1 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, pC, p1, IVY_AND, IVY_INIT_NONE) );
+ pTempA2 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Not(pC), p0, IVY_AND, IVY_INIT_NONE) );
+ if ( pTempA1 && pTempA2 )
+ {
+ pTemp = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Not(pTempA1), Ivy_Not(pTempA2), IVY_AND, IVY_INIT_NONE) );
+ if ( pTemp ) return Ivy_Not(pTemp);
+ }
+ Count0 = (pTempA1 != NULL) + (pTempA2 != NULL);
+ // implement the second MUX (F' = C * x1' + C' * x0')
+ pTempB1 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, pC, Ivy_Not(p1), IVY_AND, IVY_INIT_NONE) );
+ pTempB2 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Not(pC), Ivy_Not(p0), IVY_AND, IVY_INIT_NONE) );
+ if ( pTempB1 && pTempB2 )
+ {
+ pTemp = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Not(pTempB1), Ivy_Not(pTempB2), IVY_AND, IVY_INIT_NONE) );
+ if ( pTemp ) return pTemp;
+ }
+ Count1 = (pTempB1 != NULL) + (pTempB2 != NULL);
+ // compare and decide which one to implement
+ if ( Count0 >= Count1 )
+ {
+ pTempA1 = pTempA1? pTempA1 : Ivy_And(p, pC, p1);
+ pTempA2 = pTempA2? pTempA2 : Ivy_And(p, Ivy_Not(pC), p0);
+ return Ivy_Or( p, pTempA1, pTempA2 );
+ }
+ pTempB1 = pTempB1? pTempB1 : Ivy_And(p, pC, Ivy_Not(p1));
+ pTempB2 = pTempB2? pTempB2 : Ivy_And(p, Ivy_Not(pC), Ivy_Not(p0));
+ return Ivy_Not( Ivy_Or( p, pTempB1, pTempB2 ) );
+
+// return Ivy_Or( Ivy_And(pC, p1), Ivy_And(Ivy_Not(pC), p0) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements ITE operation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Maj( Ivy_Man_t * p, Ivy_Obj_t * pA, Ivy_Obj_t * pB, Ivy_Obj_t * pC )
+{
+ return Ivy_Or( p, Ivy_Or(p, Ivy_And(p, pA, pB), Ivy_And(p, pA, pC)), Ivy_And(p, pB, pC) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Constructs the well-balanced tree of gates.]
+
+ Description [Disregards levels and possible logic sharing.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Multi_rec( Ivy_Man_t * p, Ivy_Obj_t ** ppObjs, int nObjs, Ivy_Type_t Type )
+{
+ Ivy_Obj_t * pObj1, * pObj2;
+ if ( nObjs == 1 )
+ return ppObjs[0];
+ pObj1 = Ivy_Multi_rec( p, ppObjs, nObjs/2, Type );
+ pObj2 = Ivy_Multi_rec( p, ppObjs + nObjs/2, nObjs - nObjs/2, Type );
+ return Ivy_Oper( p, pObj1, pObj2, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Old code.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Multi( Ivy_Man_t * p, Ivy_Obj_t ** pArgs, int nArgs, Ivy_Type_t Type )
+{
+ assert( Type == IVY_AND || Type == IVY_EXOR );
+ assert( nArgs > 0 );
+ return Ivy_Multi_rec( p, pArgs, nArgs, Type );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Implements the miter.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Miter( Ivy_Man_t * p, Vec_Ptr_t * vPairs )
+{
+ int i;
+ assert( vPairs->nSize > 0 );
+ assert( vPairs->nSize % 2 == 0 );
+ // go through the cubes of the node's SOP
+ for ( i = 0; i < vPairs->nSize; i += 2 )
+ vPairs->pArray[i/2] = Ivy_Not( Ivy_Exor( p, vPairs->pArray[i], vPairs->pArray[i+1] ) );
+ vPairs->nSize = vPairs->nSize/2;
+ return Ivy_Not( Ivy_Multi_rec( p, (Ivy_Obj_t **)vPairs->pArray, vPairs->nSize, IVY_AND ) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs canonicization step.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_Latch( Ivy_Man_t * p, Ivy_Obj_t * pObj, Ivy_Init_t Init )
+{
+ return Ivy_CanonLatch( p, pObj, Init );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyResyn.c b/src/aig/ivy/ivyResyn.c
new file mode 100644
index 00000000..f42d7464
--- /dev/null
+++ b/src/aig/ivy/ivyResyn.c
@@ -0,0 +1,196 @@
+/**CFile****************************************************************
+
+ FileName [ivyResyn.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [AIG rewriting script.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyResyn.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// 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.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManResyn( 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 );
+
+// Ivy_ManRewriteAlg( pMan, fUpdateLevel, 1 );
+clk = clock();
+ Ivy_ManRewritePre( pMan, fUpdateLevel, 1, 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 );
+
+// Ivy_ManRewriteAlg( pMan, fUpdateLevel, 1 );
+clk = clock();
+ Ivy_ManRewritePre( pMan, fUpdateLevel, 1, 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.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Man_t * Ivy_ManRwsat( Ivy_Man_t * pMan, int fVerbose )
+{
+ int clk;
+ Ivy_Man_t * pTemp;
+
+if ( fVerbose ) { printf( "Original:\n" ); }
+if ( fVerbose ) Ivy_ManPrintStats( pMan );
+
+clk = clock();
+ Ivy_ManRewritePre( pMan, 0, 0, 0 );
+if ( fVerbose ) { printf( "\n" ); }
+if ( fVerbose ) { PRT( "Rewrite", clock() - clk ); }
+if ( fVerbose ) Ivy_ManPrintStats( pMan );
+
+clk = clock();
+ pMan = Ivy_ManBalance( pTemp = pMan, 0 );
+// pMan = Ivy_ManDup( pTemp = pMan );
+ Ivy_ManStop( pTemp );
+if ( fVerbose ) { printf( "\n" ); }
+if ( fVerbose ) { PRT( "Balance", clock() - clk ); }
+if ( fVerbose ) Ivy_ManPrintStats( pMan );
+
+/*
+clk = clock();
+ Ivy_ManRewritePre( pMan, 0, 0, 0 );
+if ( fVerbose ) { printf( "\n" ); }
+if ( fVerbose ) { PRT( "Rewrite", clock() - clk ); }
+if ( fVerbose ) Ivy_ManPrintStats( pMan );
+
+clk = clock();
+ pMan = Ivy_ManBalance( pTemp = pMan, 0 );
+ Ivy_ManStop( pTemp );
+if ( fVerbose ) { printf( "\n" ); }
+if ( fVerbose ) { PRT( "Balance", clock() - clk ); }
+if ( fVerbose ) Ivy_ManPrintStats( pMan );
+*/
+ return pMan;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyRwr.c b/src/aig/ivy/ivyRwr.c
new file mode 100644
index 00000000..3f8720ba
--- /dev/null
+++ b/src/aig/ivy/ivyRwr.c
@@ -0,0 +1,609 @@
+/**CFile****************************************************************
+
+ FileName [ivyRwt.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Rewriting based on precomputation.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyRwt.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+#include "deco.h"
+#include "rwt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static unsigned Ivy_NodeGetTruth( Ivy_Obj_t * pObj, int * pNums, int nNums );
+static int Ivy_NodeRewrite( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUpdateLevel, int fUseZeroCost );
+static Dec_Graph_t * Rwt_CutEvaluate( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pRoot,
+ Vec_Ptr_t * vFaninsCur, int nNodesSaved, int LevelMax, int * pGainBest, unsigned uTruth );
+
+static int Ivy_GraphToNetworkCount( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax, int LevelMax );
+static void Ivy_GraphUpdateNetwork( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int fUpdateLevel, int nGain );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Performs incremental rewriting of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManRewritePre( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost, int fVerbose )
+{
+ Rwt_Man_t * pManRwt;
+ Ivy_Obj_t * pNode;
+ int i, nNodes, nGain;
+ int clk, clkStart = clock();
+ // start the rewriting manager
+ pManRwt = Rwt_ManStart( 0 );
+ p->pData = pManRwt;
+ if ( pManRwt == NULL )
+ return 0;
+ // create fanouts
+ if ( fUpdateLevel && p->fFanout == 0 )
+ Ivy_ManStartFanout( p );
+ // compute the reverse levels if level update is requested
+ if ( fUpdateLevel )
+ Ivy_ManRequiredLevels( p );
+ // set the number of levels
+// p->nLevelMax = Ivy_ManLevels( p );
+ // resynthesize each node once
+ nNodes = Ivy_ManObjIdMax(p);
+ Ivy_ManForEachNode( p, pNode, i )
+ {
+ // fix the fanin buffer problem
+ Ivy_NodeFixBufferFanins( p, pNode, 1 );
+ if ( Ivy_ObjIsBuf(pNode) )
+ continue;
+ // stop if all nodes have been tried once
+ if ( i > nNodes )
+ break;
+ // for each cut, try to resynthesize it
+ nGain = Ivy_NodeRewrite( p, pManRwt, pNode, fUpdateLevel, fUseZeroCost );
+ if ( nGain > 0 || nGain == 0 && fUseZeroCost )
+ {
+ Dec_Graph_t * pGraph = Rwt_ManReadDecs(pManRwt);
+ int fCompl = Rwt_ManReadCompl(pManRwt);
+/*
+ {
+ Ivy_Obj_t * pObj;
+ int i;
+ printf( "USING: (" );
+ Vec_PtrForEachEntry( Rwt_ManReadLeaves(pManRwt), pObj, i )
+ printf( "%d ", Ivy_ObjFanoutNum(Ivy_Regular(pObj)) );
+ printf( ") Gain = %d.\n", nGain );
+ }
+ if ( nGain > 0 )
+ { // print stats on the MFFC
+ extern void Ivy_NodeMffsConeSuppPrint( Ivy_Obj_t * pNode );
+ printf( "Node %6d : Gain = %4d ", pNode->Id, nGain );
+ Ivy_NodeMffsConeSuppPrint( pNode );
+ }
+*/
+ // complement the FF if needed
+clk = clock();
+ if ( fCompl ) Dec_GraphComplement( pGraph );
+ Ivy_GraphUpdateNetwork( p, pNode, pGraph, fUpdateLevel, nGain );
+ if ( fCompl ) Dec_GraphComplement( pGraph );
+Rwt_ManAddTimeUpdate( pManRwt, clock() - clk );
+ }
+ }
+Rwt_ManAddTimeTotal( pManRwt, clock() - clkStart );
+ // print stats
+ if ( fVerbose )
+ Rwt_ManPrintStats( pManRwt );
+ // delete the managers
+ Rwt_ManStop( pManRwt );
+ p->pData = NULL;
+ // fix the levels
+ if ( fUpdateLevel )
+ Vec_IntFree( p->vRequired ), p->vRequired = NULL;
+ else
+ Ivy_ManResetLevels( p );
+ // check
+ if ( i = Ivy_ManCleanup(p) )
+ printf( "Cleanup after rewriting removed %d dangling nodes.\n", i );
+ if ( !Ivy_ManCheck(p) )
+ printf( "Ivy_ManRewritePre(): The check has failed.\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs rewriting for one node.]
+
+ Description [This procedure considers all the cuts computed for the node
+ and tries to rewrite each of them using the "forest" of different AIG
+ structures precomputed and stored in the RWR manager.
+ Determines the best rewriting and computes the gain in the number of AIG
+ nodes in the final network. In the end, p->vFanins contains information
+ about the best cut that can be used for rewriting, while p->pGraph gives
+ the decomposition dag (represented using decomposition graph data structure).
+ Returns gain in the number of nodes or -1 if node cannot be rewritten.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeRewrite( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUpdateLevel, int fUseZeroCost )
+{
+ int fVeryVerbose = 0;
+ Dec_Graph_t * pGraph;
+ Ivy_Store_t * pStore;
+ Ivy_Cut_t * pCut;
+ Ivy_Obj_t * pFanin;
+ unsigned uPhase, uTruthBest, uTruth;
+ char * pPerm;
+ int Required, nNodesSaved, nNodesSaveCur;
+ int i, c, GainCur, GainBest = -1;
+ int clk, clk2;
+
+ p->nNodesConsidered++;
+ // get the required times
+ Required = fUpdateLevel? Vec_IntEntry( pMan->vRequired, pNode->Id ) : 1000000;
+ // get the node's cuts
+clk = clock();
+ pStore = Ivy_NodeFindCutsAll( pMan, pNode, 5 );
+p->timeCut += clock() - clk;
+
+ // go through the cuts
+clk = clock();
+ for ( c = 1; c < pStore->nCuts; c++ )
+ {
+ pCut = pStore->pCuts + c;
+ // consider only 4-input cuts
+ if ( pCut->nSize != 4 )
+ continue;
+ // skip the cuts with buffers
+ for ( i = 0; i < (int)pCut->nSize; i++ )
+ if ( Ivy_ObjIsBuf( Ivy_ManObj(pMan, pCut->pArray[i]) ) )
+ break;
+ if ( i != pCut->nSize )
+ {
+ p->nCutsBad++;
+ continue;
+ }
+ p->nCutsGood++;
+ // get the fanin permutation
+clk2 = clock();
+ uTruth = 0xFFFF & Ivy_NodeGetTruth( pNode, pCut->pArray, pCut->nSize ); // truth table
+p->timeTruth += clock() - clk2;
+ pPerm = p->pPerms4[ p->pPerms[uTruth] ];
+ uPhase = p->pPhases[uTruth];
+ // collect fanins with the corresponding permutation/phase
+ Vec_PtrClear( p->vFaninsCur );
+ Vec_PtrFill( p->vFaninsCur, (int)pCut->nSize, 0 );
+ for ( i = 0; i < (int)pCut->nSize; i++ )
+ {
+ pFanin = Ivy_ManObj( pMan, pCut->pArray[pPerm[i]] );
+ assert( Ivy_ObjIsNode(pFanin) || Ivy_ObjIsCi(pFanin) );
+ pFanin = Ivy_NotCond(pFanin, ((uPhase & (1<<i)) > 0) );
+ Vec_PtrWriteEntry( p->vFaninsCur, i, pFanin );
+ }
+clk2 = clock();
+/*
+ printf( "Considering: (" );
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ printf( "%d ", Ivy_ObjFanoutNum(Ivy_Regular(pFanin)) );
+ printf( ")\n" );
+*/
+ // mark the fanin boundary
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ Ivy_ObjRefsInc( Ivy_Regular(pFanin) );
+ // label MFFC with current ID
+ Ivy_ManIncrementTravId( pMan );
+ nNodesSaved = Ivy_ObjMffcLabel( pMan, pNode );
+ // unmark the fanin boundary
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ Ivy_ObjRefsDec( Ivy_Regular(pFanin) );
+p->timeMffc += clock() - clk2;
+
+ // evaluate the cut
+clk2 = clock();
+ pGraph = Rwt_CutEvaluate( pMan, p, pNode, p->vFaninsCur, nNodesSaved, Required, &GainCur, uTruth );
+p->timeEval += clock() - clk2;
+
+ // check if the cut is better than the current best one
+ if ( pGraph != NULL && GainBest < GainCur )
+ {
+ // save this form
+ nNodesSaveCur = nNodesSaved;
+ GainBest = GainCur;
+ p->pGraph = pGraph;
+ p->fCompl = ((uPhase & (1<<4)) > 0);
+ uTruthBest = uTruth;
+ // collect fanins in the
+ Vec_PtrClear( p->vFanins );
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ Vec_PtrPush( p->vFanins, pFanin );
+ }
+ }
+p->timeRes += clock() - clk;
+
+ if ( GainBest == -1 )
+ return -1;
+
+// printf( "%d", nNodesSaveCur - GainBest );
+/*
+ if ( GainBest > 0 )
+ {
+ if ( Rwt_CutIsintean( pNode, p->vFanins ) )
+ printf( "b" );
+ else
+ {
+ printf( "Node %d : ", pNode->Id );
+ Vec_PtrForEachEntry( p->vFanins, pFanin, i )
+ printf( "%d ", Ivy_Regular(pFanin)->Id );
+ printf( "a" );
+ }
+ }
+*/
+/*
+ if ( GainBest > 0 )
+ if ( p->fCompl )
+ printf( "c" );
+ else
+ printf( "." );
+*/
+
+ // copy the leaves
+ Vec_PtrForEachEntry( p->vFanins, pFanin, i )
+ Dec_GraphNode(p->pGraph, i)->pFunc = pFanin;
+
+ p->nScores[p->pMap[uTruthBest]]++;
+ p->nNodesGained += GainBest;
+ if ( fUseZeroCost || GainBest > 0 )
+ p->nNodesRewritten++;
+
+ // report the progress
+ if ( fVeryVerbose && GainBest > 0 )
+ {
+ printf( "Node %6d : ", Ivy_ObjId(pNode) );
+ printf( "Fanins = %d. ", p->vFanins->nSize );
+ printf( "Save = %d. ", nNodesSaveCur );
+ printf( "Add = %d. ", nNodesSaveCur-GainBest );
+ printf( "GAIN = %d. ", GainBest );
+ printf( "Cone = %d. ", p->pGraph? Dec_GraphNodeNum(p->pGraph) : 0 );
+ printf( "Class = %d. ", p->pMap[uTruthBest] );
+ printf( "\n" );
+ }
+ return GainBest;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes the truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_NodeGetTruth_rec( Ivy_Obj_t * pObj, int * pNums, int nNums )
+{
+ static unsigned uMasks[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
+ unsigned uTruth0, uTruth1;
+ int i;
+ for ( i = 0; i < nNums; i++ )
+ if ( pObj->Id == pNums[i] )
+ return uMasks[i];
+ assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj) );
+ uTruth0 = Ivy_NodeGetTruth_rec( Ivy_ObjFanin0(pObj), pNums, nNums );
+ if ( Ivy_ObjFaninC0(pObj) )
+ uTruth0 = ~uTruth0;
+ if ( Ivy_ObjIsBuf(pObj) )
+ return uTruth0;
+ uTruth1 = Ivy_NodeGetTruth_rec( Ivy_ObjFanin1(pObj), pNums, nNums );
+ if ( Ivy_ObjFaninC1(pObj) )
+ uTruth1 = ~uTruth1;
+ return uTruth0 & uTruth1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_NodeGetTruth( Ivy_Obj_t * pObj, int * pNums, int nNums )
+{
+ assert( nNums < 6 );
+ return Ivy_NodeGetTruth_rec( pObj, pNums, nNums );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Evaluates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dec_Graph_t * Rwt_CutEvaluate( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pRoot, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int LevelMax, int * pGainBest, unsigned uTruth )
+{
+ Vec_Ptr_t * vSubgraphs;
+ Dec_Graph_t * pGraphBest, * pGraphCur;
+ Rwt_Node_t * pNode, * pFanin;
+ int nNodesAdded, GainBest, i, k;
+ // find the matching class of subgraphs
+ vSubgraphs = Vec_VecEntry( p->vClasses, p->pMap[uTruth] );
+ p->nSubgraphs += vSubgraphs->nSize;
+ // determine the best subgraph
+ GainBest = -1;
+ Vec_PtrForEachEntry( vSubgraphs, pNode, i )
+ {
+ // get the current graph
+ pGraphCur = (Dec_Graph_t *)pNode->pNext;
+ // copy the leaves
+ Vec_PtrForEachEntry( vFaninsCur, pFanin, k )
+ Dec_GraphNode(pGraphCur, k)->pFunc = pFanin;
+ // detect how many unlabeled nodes will be reused
+ nNodesAdded = Ivy_GraphToNetworkCount( pMan, pRoot, pGraphCur, nNodesSaved, LevelMax );
+ if ( nNodesAdded == -1 )
+ continue;
+ assert( nNodesSaved >= nNodesAdded );
+ // count the gain at this node
+ if ( GainBest < nNodesSaved - nNodesAdded )
+ {
+ GainBest = nNodesSaved - nNodesAdded;
+ pGraphBest = pGraphCur;
+ }
+ }
+ if ( GainBest == -1 )
+ return NULL;
+ *pGainBest = GainBest;
+ return pGraphBest;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of new nodes added when using this graph.]
+
+ Description [AIG nodes for the fanins should be assigned to pNode->pFunc
+ of the leaves of the graph before calling this procedure.
+ Returns -1 if the number of nodes and levels exceeded the given limit or
+ the number of levels exceeded the maximum allowed level.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_GraphToNetworkCount( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax, int LevelMax )
+{
+ Dec_Node_t * pNode, * pNode0, * pNode1;
+ Ivy_Obj_t * pAnd, * pAnd0, * pAnd1;
+ int i, Counter, LevelNew, LevelOld;
+ // check for constant function or a literal
+ if ( Dec_GraphIsConst(pGraph) || Dec_GraphIsVar(pGraph) )
+ return 0;
+ // set the levels of the leaves
+ Dec_GraphForEachLeaf( pGraph, pNode, i )
+ pNode->Level = Ivy_Regular(pNode->pFunc)->Level;
+ // compute the AIG size after adding the internal nodes
+ Counter = 0;
+ Dec_GraphForEachNode( pGraph, pNode, i )
+ {
+ // get the children of this node
+ pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
+ pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
+ // get the AIG nodes corresponding to the children
+ pAnd0 = pNode0->pFunc;
+ pAnd1 = pNode1->pFunc;
+ if ( pAnd0 && pAnd1 )
+ {
+ // if they are both present, find the resulting node
+ pAnd0 = Ivy_NotCond( pAnd0, pNode->eEdge0.fCompl );
+ pAnd1 = Ivy_NotCond( pAnd1, pNode->eEdge1.fCompl );
+ pAnd = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, pAnd0, pAnd1, IVY_AND, IVY_INIT_NONE) );
+ // return -1 if the node is the same as the original root
+ if ( Ivy_Regular(pAnd) == pRoot )
+ return -1;
+ }
+ else
+ pAnd = NULL;
+ // count the number of added nodes
+ if ( pAnd == NULL || Ivy_ObjIsTravIdCurrent(p, Ivy_Regular(pAnd)) )
+ {
+ if ( ++Counter > NodeMax )
+ return -1;
+ }
+ // count the number of new levels
+ LevelNew = 1 + RWT_MAX( pNode0->Level, pNode1->Level );
+ if ( pAnd )
+ {
+ if ( Ivy_Regular(pAnd) == p->pConst1 )
+ LevelNew = 0;
+ else if ( Ivy_Regular(pAnd) == Ivy_Regular(pAnd0) )
+ LevelNew = (int)Ivy_Regular(pAnd0)->Level;
+ else if ( Ivy_Regular(pAnd) == Ivy_Regular(pAnd1) )
+ LevelNew = (int)Ivy_Regular(pAnd1)->Level;
+ LevelOld = (int)Ivy_Regular(pAnd)->Level;
+// assert( LevelNew == LevelOld );
+ }
+ if ( LevelNew > LevelMax )
+ return -1;
+ pNode->pFunc = pAnd;
+ pNode->Level = LevelNew;
+ }
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the decomposition graph into the AIG.]
+
+ Description [AIG nodes for the fanins should be assigned to pNode->pFunc
+ of the leaves of the graph before calling this procedure.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_GraphToNetwork( Ivy_Man_t * p, Dec_Graph_t * pGraph )
+{
+ Ivy_Obj_t * pAnd0, * pAnd1;
+ Dec_Node_t * pNode;
+ int i;
+ // check for constant function
+ if ( Dec_GraphIsConst(pGraph) )
+ return Ivy_NotCond( Ivy_ManConst1(p), Dec_GraphIsComplement(pGraph) );
+ // check for a literal
+ if ( Dec_GraphIsVar(pGraph) )
+ return Ivy_NotCond( Dec_GraphVar(pGraph)->pFunc, Dec_GraphIsComplement(pGraph) );
+ // build the AIG nodes corresponding to the AND gates of the graph
+ Dec_GraphForEachNode( pGraph, pNode, i )
+ {
+ pAnd0 = Ivy_NotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl );
+ pAnd1 = Ivy_NotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl );
+ pNode->pFunc = Ivy_And( p, pAnd0, pAnd1 );
+ }
+ // complement the result if necessary
+ return Ivy_NotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces MFFC of the node by the new factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_GraphUpdateNetwork( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int fUpdateLevel, int nGain )
+{
+ Ivy_Obj_t * pRootNew;
+ int nNodesNew, nNodesOld, Required;
+ Required = fUpdateLevel? Vec_IntEntry( p->vRequired, pRoot->Id ) : 1000000;
+ nNodesOld = Ivy_ManNodeNum(p);
+ // create the new structure of nodes
+ pRootNew = Ivy_GraphToNetwork( p, pGraph );
+ assert( (int)Ivy_Regular(pRootNew)->Level <= Required );
+// if ( Ivy_Regular(pRootNew)->Level == Required )
+// printf( "Difference %d.\n", Ivy_Regular(pRootNew)->Level - Required );
+ // remove the old nodes
+// Ivy_AigReplace( pMan->pManFunc, pRoot, pRootNew, fUpdateLevel );
+/*
+ if ( Ivy_IsComplement(pRootNew) )
+ printf( "c" );
+ else
+ printf( "d" );
+ if ( Ivy_ObjRefs(Ivy_Regular(pRootNew)) > 0 )
+ printf( "%d", Ivy_ObjRefs(Ivy_Regular(pRootNew)) );
+ printf( " " );
+*/
+ Ivy_ObjReplace( p, pRoot, pRootNew, 1, 0, 1 );
+ // compare the gains
+ nNodesNew = Ivy_ManNodeNum(p);
+ assert( nGain <= nNodesOld - nNodesNew );
+ // propagate the buffer
+ Ivy_ManPropagateBuffers( p, 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces MFFC of the node by the new factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_GraphUpdateNetwork3( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int fUpdateLevel, int nGain )
+{
+ Ivy_Obj_t * pRootNew, * pFanin;
+ int nNodesNew, nNodesOld, i, nRefsOld;
+ nNodesOld = Ivy_ManNodeNum(p);
+
+//printf( "Before = %d. ", Ivy_ManNodeNum(p) );
+ // mark the cut
+ Vec_PtrForEachEntry( ((Rwt_Man_t *)p->pData)->vFanins, pFanin, i )
+ Ivy_ObjRefsInc( Ivy_Regular(pFanin) );
+ // deref the old cone
+ nRefsOld = pRoot->nRefs;
+ pRoot->nRefs = 0;
+ Ivy_ObjDelete_rec( p, pRoot, 0 );
+ pRoot->nRefs = nRefsOld;
+ // unmark the cut
+ Vec_PtrForEachEntry( ((Rwt_Man_t *)p->pData)->vFanins, pFanin, i )
+ Ivy_ObjRefsDec( Ivy_Regular(pFanin) );
+//printf( "Deref = %d. ", Ivy_ManNodeNum(p) );
+
+ // create the new structure of nodes
+ pRootNew = Ivy_GraphToNetwork( p, pGraph );
+//printf( "Create = %d. ", Ivy_ManNodeNum(p) );
+ // remove the old nodes
+// Ivy_AigReplace( pMan->pManFunc, pRoot, pRootNew, fUpdateLevel );
+/*
+ if ( Ivy_IsComplement(pRootNew) )
+ printf( "c" );
+ else
+ printf( "d" );
+ if ( Ivy_ObjRefs(Ivy_Regular(pRootNew)) > 0 )
+ printf( "%d", Ivy_ObjRefs(Ivy_Regular(pRootNew)) );
+ printf( " " );
+*/
+ Ivy_ObjReplace( p, pRoot, pRootNew, 0, 0, 1 );
+//printf( "Replace = %d. ", Ivy_ManNodeNum(p) );
+
+ // delete remaining dangling nodes
+ Vec_PtrForEachEntry( ((Rwt_Man_t *)p->pData)->vFanins, pFanin, i )
+ {
+ pFanin = Ivy_Regular(pFanin);
+ if ( !Ivy_ObjIsNone(pFanin) && Ivy_ObjRefs(pFanin) == 0 )
+ Ivy_ObjDelete_rec( p, pFanin, 1 );
+ }
+//printf( "Deref = %d. ", Ivy_ManNodeNum(p) );
+//printf( "\n" );
+
+ // compare the gains
+ nNodesNew = Ivy_ManNodeNum(p);
+ assert( nGain <= nNodesOld - nNodesNew );
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyRwrAlg.c b/src/aig/ivy/ivyRwrAlg.c
new file mode 100644
index 00000000..fc48deb0
--- /dev/null
+++ b/src/aig/ivy/ivyRwrAlg.c
@@ -0,0 +1,408 @@
+/**CFile****************************************************************
+
+ FileName [ivyRwrAlg.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Algebraic AIG rewriting.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyRwrAlg.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Ivy_ManFindAlgCut( Ivy_Obj_t * pRoot, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone );
+static Ivy_Obj_t * Ivy_NodeRewriteAlg( Ivy_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Vec_Ptr_t * vSols, int LevelR, int fUseZeroCost );
+static int Ivy_NodeCountMffc( Ivy_Obj_t * pNode );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Algebraic AIG rewriting.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManRewriteAlg( Ivy_Man_t * p, int fUpdateLevel, int fUseZeroCost )
+{
+ Vec_Int_t * vRequired;
+ Vec_Ptr_t * vFront, * vLeaves, * vCone, * vSol;
+ Ivy_Obj_t * pObj, * pResult;
+ int i, RetValue, LevelR, nNodesOld;
+ int CountUsed, CountUndo;
+ vRequired = fUpdateLevel? Ivy_ManRequiredLevels( p ) : NULL;
+ vFront = Vec_PtrAlloc( 100 );
+ vLeaves = Vec_PtrAlloc( 100 );
+ vCone = Vec_PtrAlloc( 100 );
+ vSol = Vec_PtrAlloc( 100 );
+ // go through the nodes in the topological order
+ CountUsed = CountUndo = 0;
+ nNodesOld = Ivy_ManObjIdNext(p);
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ assert( !Ivy_ObjIsBuf(pObj) );
+ if ( i >= nNodesOld )
+ break;
+ // skip no-nodes and MUX roots
+ if ( !Ivy_ObjIsNode(pObj) || Ivy_ObjIsExor(pObj) || Ivy_ObjIsMuxType(pObj) )
+ continue;
+// if ( pObj->Id > 297 ) // 296 --- 297
+// break;
+ if ( pObj->Id == 297 )
+ {
+ int x = 0;
+ }
+ // get the largest algebraic cut
+ RetValue = Ivy_ManFindAlgCut( pObj, vFront, vLeaves, vCone );
+ // the case of a trivial tree cut
+ if ( RetValue == 1 )
+ continue;
+ // the case of constant 0 cone
+ if ( RetValue == -1 )
+ {
+ Ivy_ObjReplace( pObj, Ivy_ManConst0(p), 1, 0, 1 );
+ continue;
+ }
+ assert( Vec_PtrSize(vLeaves) > 2 );
+ // get the required level for this node
+ LevelR = vRequired? Vec_IntEntry(vRequired, pObj->Id) : 1000000;
+ // create a new cone
+ pResult = Ivy_NodeRewriteAlg( pObj, vFront, vLeaves, vCone, vSol, LevelR, fUseZeroCost );
+ if ( pResult == NULL || pResult == pObj )
+ continue;
+ assert( Vec_PtrSize(vSol) == 1 || !Ivy_IsComplement(pResult) );
+ if ( Ivy_ObjLevel(Ivy_Regular(pResult)) > LevelR && Ivy_ObjRefs(Ivy_Regular(pResult)) == 0 )
+ Ivy_ObjDelete_rec(Ivy_Regular(pResult), 1), CountUndo++;
+ else
+ Ivy_ObjReplace( pObj, pResult, 1, 0, 1 ), CountUsed++;
+ }
+ printf( "Used = %d. Undo = %d.\n", CountUsed, CountUndo );
+ Vec_PtrFree( vFront );
+ Vec_PtrFree( vCone );
+ Vec_PtrFree( vSol );
+ if ( vRequired ) Vec_IntFree( vRequired );
+ if ( i = Ivy_ManCleanup(p) )
+ printf( "Cleanup after rewriting removed %d dangling nodes.\n", i );
+ if ( !Ivy_ManCheck(p) )
+ printf( "Ivy_ManRewriteAlg(): The check has failed.\n" );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Analizes one node.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_NodeRewriteAlg( Ivy_Obj_t * pObj, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone, Vec_Ptr_t * vSols, int LevelR, int fUseZeroCost )
+{
+ int fVerbose = 0;
+ Ivy_Obj_t * pTemp;
+ int k, Counter, nMffc, RetValue;
+
+ if ( fVerbose )
+ {
+ if ( Ivy_ObjIsExor(pObj) )
+ printf( "x " );
+ else
+ printf( " " );
+ }
+
+/*
+ printf( "%d ", Vec_PtrSize(vFront) );
+ printf( "( " );
+ Vec_PtrForEachEntry( vFront, pTemp, k )
+ printf( "%d ", Ivy_ObjRefs(Ivy_Regular(pTemp)) );
+ printf( ")\n" );
+*/
+ // collect nodes in the cone
+ if ( Ivy_ObjIsExor(pObj) )
+ Ivy_ManCollectCone( pObj, vFront, vCone );
+ else
+ Ivy_ManCollectCone( pObj, vLeaves, vCone );
+
+ // deref nodes in the cone
+ Vec_PtrForEachEntry( vCone, pTemp, k )
+ {
+ Ivy_ObjRefsDec( Ivy_ObjFanin0(pTemp) );
+ Ivy_ObjRefsDec( Ivy_ObjFanin1(pTemp) );
+ pTemp->fMarkB = 1;
+ }
+
+ // count the MFFC size
+ Vec_PtrForEachEntry( vFront, pTemp, k )
+ Ivy_Regular(pTemp)->fMarkA = 1;
+ nMffc = Ivy_NodeCountMffc( pObj );
+ Vec_PtrForEachEntry( vFront, pTemp, k )
+ Ivy_Regular(pTemp)->fMarkA = 0;
+
+ if ( fVerbose )
+ {
+ Counter = 0;
+ Vec_PtrForEachEntry( vCone, pTemp, k )
+ Counter += (Ivy_ObjRefs(pTemp) > 0);
+ printf( "%5d : Leaves = %2d. Cone = %2d. ConeRef = %2d. Mffc = %d. Lev = %d. LevR = %d.\n",
+ pObj->Id, Vec_PtrSize(vFront), Vec_PtrSize(vCone), Counter-1, nMffc, Ivy_ObjLevel(pObj), LevelR );
+ }
+/*
+ printf( "Leaves:" );
+ Vec_PtrForEachEntry( vLeaves, pTemp, k )
+ printf( " %d%s", Ivy_Regular(pTemp)->Id, Ivy_IsComplement(pTemp)? "\'" : "" );
+ printf( "\n" );
+ printf( "Cone:\n" );
+ Vec_PtrForEachEntry( vCone, pTemp, k )
+ printf( " %5d = %d%s %d%s\n", pTemp->Id,
+ Ivy_ObjFaninId0(pTemp), Ivy_ObjFaninC0(pTemp)? "\'" : "",
+ Ivy_ObjFaninId1(pTemp), Ivy_ObjFaninC1(pTemp)? "\'" : "" );
+*/
+
+ RetValue = Ivy_MultiPlus( vLeaves, vCone, Ivy_ObjType(pObj), nMffc + fUseZeroCost, vSols );
+
+ // ref nodes in the cone
+ Vec_PtrForEachEntry( vCone, pTemp, k )
+ {
+ Ivy_ObjRefsInc( Ivy_ObjFanin0(pTemp) );
+ Ivy_ObjRefsInc( Ivy_ObjFanin1(pTemp) );
+ pTemp->fMarkA = 0;
+ pTemp->fMarkB = 0;
+ }
+
+ if ( !RetValue )
+ return NULL;
+
+ if ( Vec_PtrSize( vSols ) == 1 )
+ return Vec_PtrEntry( vSols, 0 );
+ return Ivy_NodeBalanceBuildSuper( vSols, Ivy_ObjType(pObj), 1 );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison for node pointers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeCountMffc_rec( Ivy_Obj_t * pNode )
+{
+ if ( Ivy_ObjRefs(pNode) > 0 || Ivy_ObjIsCi(pNode) || pNode->fMarkA )
+ return 0;
+ assert( pNode->fMarkB );
+ pNode->fMarkA = 1;
+// printf( "%d ", pNode->Id );
+ if ( Ivy_ObjIsBuf(pNode) )
+ return Ivy_NodeCountMffc_rec( Ivy_ObjFanin0(pNode) );
+ return 1 + Ivy_NodeCountMffc_rec( Ivy_ObjFanin0(pNode) ) + Ivy_NodeCountMffc_rec( Ivy_ObjFanin1(pNode) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison for node pointers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeCountMffc( Ivy_Obj_t * pNode )
+{
+ assert( pNode->fMarkB );
+ return 1 + Ivy_NodeCountMffc_rec( Ivy_ObjFanin0(pNode) ) + Ivy_NodeCountMffc_rec( Ivy_ObjFanin1(pNode) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Comparison for node pointers.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManFindAlgCutCompare( Ivy_Obj_t ** pp1, Ivy_Obj_t ** pp2 )
+{
+ if ( *pp1 < *pp2 )
+ return -1;
+ if ( *pp1 > *pp2 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computing one algebraic cut.]
+
+ Description [Returns 1 if the tree-leaves of this node where traversed
+ and found to have no external references (and have not been collected).
+ Returns 0 if the tree-leaves have external references and are collected.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManFindAlgCut_rec( Ivy_Obj_t * pObj, Ivy_Type_t Type, Vec_Ptr_t * vFront, Vec_Ptr_t * vCone )
+{
+ int RetValue0, RetValue1;
+ Ivy_Obj_t * pObjR = Ivy_Regular(pObj);
+ assert( !Ivy_ObjIsBuf(pObjR) );
+ assert( Type != IVY_EXOR || !Ivy_IsComplement(pObj) );
+
+ // make sure the node is not visited twice in different polarities
+ if ( Ivy_IsComplement(pObj) )
+ { // if complemented, mark B
+ if ( pObjR->fMarkA )
+ return -1;
+ pObjR->fMarkB = 1;
+ }
+ else
+ { // if non-complicated, mark A
+ if ( pObjR->fMarkB )
+ return -1;
+ pObjR->fMarkA = 1;
+ }
+ Vec_PtrPush( vCone, pObjR );
+
+ // if the node is the end of the tree, return
+ if ( Ivy_IsComplement(pObj) || Ivy_ObjType(pObj) != Type )
+ {
+ if ( Ivy_ObjRefs(pObjR) == 1 )
+ return 1;
+ assert( Ivy_ObjRefs(pObjR) > 1 );
+ Vec_PtrPush( vFront, pObj );
+ return 0;
+ }
+
+ // branch on the node
+ assert( !Ivy_IsComplement(pObj) );
+ assert( Ivy_ObjIsNode(pObj) );
+ // what if buffer has more than one fanout???
+ RetValue0 = Ivy_ManFindAlgCut_rec( Ivy_ObjReal( Ivy_ObjChild0(pObj) ), Type, vFront, vCone );
+ RetValue1 = Ivy_ManFindAlgCut_rec( Ivy_ObjReal( Ivy_ObjChild1(pObj) ), Type, vFront, vCone );
+ if ( RetValue0 == -1 || RetValue1 == -1 )
+ return -1;
+
+ // the case when both have no external references
+ if ( RetValue0 && RetValue1 )
+ {
+ if ( Ivy_ObjRefs(pObj) == 1 )
+ return 1;
+ assert( Ivy_ObjRefs(pObj) > 1 );
+ Vec_PtrPush( vFront, pObj );
+ return 0;
+ }
+ // the case when one of them has external references
+ if ( RetValue0 )
+ Vec_PtrPush( vFront, Ivy_ObjReal( Ivy_ObjChild0(pObj) ) );
+ if ( RetValue1 )
+ Vec_PtrPush( vFront, Ivy_ObjReal( Ivy_ObjChild1(pObj) ) );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computing one algebraic cut.]
+
+ Description [Algebraic cut stops when we hit (a) CI, (b) complemented edge,
+ (c) boundary of different gates. Returns 1 if this is a pure tree.
+ Returns -1 if the contant 0 is detected. Return 0 if the array can be used.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManFindAlgCut( Ivy_Obj_t * pRoot, Vec_Ptr_t * vFront, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vCone )
+{
+ Ivy_Obj_t * pObj, * pPrev;
+ int RetValue, i;
+ assert( !Ivy_IsComplement(pRoot) );
+ assert( Ivy_ObjIsNode(pRoot) );
+ // clear the frontier and collect the nodes
+ Vec_PtrClear( vCone );
+ Vec_PtrClear( vFront );
+ Vec_PtrClear( vLeaves );
+ RetValue = Ivy_ManFindAlgCut_rec( pRoot, Ivy_ObjType(pRoot), vFront, vCone );
+ // clean the marks
+ Vec_PtrForEachEntry( vCone, pObj, i )
+ pObj->fMarkA = pObj->fMarkB = 0;
+ // quit if the same node is found in both polarities
+ if ( RetValue == -1 )
+ return -1;
+ // return if the node is the root of a tree
+ if ( RetValue == 1 )
+ return 1;
+ // return if the cut is composed of two nodes
+ if ( Vec_PtrSize(vFront) <= 2 )
+ return 1;
+ // sort the entries in increasing order
+ Vec_PtrSort( vFront, Ivy_ManFindAlgCutCompare );
+ // remove duplicates from vFront and save the nodes in vLeaves
+ pPrev = Vec_PtrEntry(vFront, 0);
+ Vec_PtrPush( vLeaves, pPrev );
+ Vec_PtrForEachEntryStart( vFront, pObj, i, 1 )
+ {
+ // compare current entry and the previous entry
+ if ( pObj == pPrev )
+ {
+ if ( Ivy_ObjIsExor(pRoot) ) // A <+> A = 0
+ {
+ // vLeaves are no longer structural support of pRoot!!!
+ Vec_PtrPop(vLeaves);
+ pPrev = Vec_PtrSize(vLeaves) == 0 ? NULL : Vec_PtrEntryLast(vLeaves);
+ }
+ continue;
+ }
+ if ( pObj == Ivy_Not(pPrev) )
+ {
+ assert( Ivy_ObjIsAnd(pRoot) );
+ return -1;
+ }
+ pPrev = pObj;
+ Vec_PtrPush( vLeaves, pObj );
+ }
+ if ( Vec_PtrSize(vLeaves) == 0 )
+ return -1;
+ if ( Vec_PtrSize(vLeaves) <= 2 )
+ return 1;
+ return 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivySeq.c b/src/aig/ivy/ivySeq.c
new file mode 100644
index 00000000..0ee29fee
--- /dev/null
+++ b/src/aig/ivy/ivySeq.c
@@ -0,0 +1,1134 @@
+/**CFile****************************************************************
+
+ FileName [ivySeq.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis []
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivySeq.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+#include "deco.h"
+#include "rwt.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static int Ivy_NodeRewriteSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUseZeroCost );
+static void Ivy_GraphPrepare( Dec_Graph_t * pGraph, Ivy_Cut_t * pCut, Vec_Ptr_t * vFanins, char * pPerm );
+static unsigned Ivy_CutGetTruth( Ivy_Man_t * p, Ivy_Obj_t * pObj, int * pNums, int nNums );
+static Dec_Graph_t * Rwt_CutEvaluateSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pRoot, Ivy_Cut_t * pCut, char * pPerm, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int * pGainBest, unsigned uTruth );
+static int Ivy_GraphToNetworkSeqCountSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax );
+static Ivy_Obj_t * Ivy_GraphToNetworkSeq( Ivy_Man_t * p, Dec_Graph_t * pGraph );
+static void Ivy_GraphUpdateNetworkSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int nGain );
+static Ivy_Store_t * Ivy_CutComputeForNode( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves );
+
+static inline int Ivy_CutHashValue( int NodeId ) { return 1 << (NodeId % 31); }
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+//int nMoves;
+//int nMovesS;
+//int nClauses;
+//int timeInv;
+
+/**Function*************************************************************
+
+ Synopsis [Performs incremental rewriting of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManRewriteSeq( Ivy_Man_t * p, int fUseZeroCost, int fVerbose )
+{
+ Rwt_Man_t * pManRwt;
+ Ivy_Obj_t * pNode;
+ int i, nNodes, nGain;
+ int clk, clkStart = clock();
+
+ // set the DC latch values
+ Ivy_ManForEachLatch( p, pNode, i )
+ pNode->Init = IVY_INIT_DC;
+ // start the rewriting manager
+ pManRwt = Rwt_ManStart( 0 );
+ p->pData = pManRwt;
+ if ( pManRwt == NULL )
+ return 0;
+ // create fanouts
+ if ( p->fFanout == 0 )
+ Ivy_ManStartFanout( p );
+ // resynthesize each node once
+ nNodes = Ivy_ManObjIdMax(p);
+ Ivy_ManForEachNode( p, pNode, i )
+ {
+ assert( !Ivy_ObjIsBuf(pNode) );
+ assert( !Ivy_ObjIsBuf(Ivy_ObjFanin0(pNode)) );
+ assert( !Ivy_ObjIsBuf(Ivy_ObjFanin1(pNode)) );
+ // fix the fanin buffer problem
+// Ivy_NodeFixBufferFanins( p, pNode );
+// if ( Ivy_ObjIsBuf(pNode) )
+// continue;
+ // stop if all nodes have been tried once
+ if ( i > nNodes )
+ break;
+ // for each cut, try to resynthesize it
+ nGain = Ivy_NodeRewriteSeq( p, pManRwt, pNode, fUseZeroCost );
+ if ( nGain > 0 || nGain == 0 && fUseZeroCost )
+ {
+ Dec_Graph_t * pGraph = Rwt_ManReadDecs(pManRwt);
+ int fCompl = Rwt_ManReadCompl(pManRwt);
+ // complement the FF if needed
+clk = clock();
+ if ( fCompl ) Dec_GraphComplement( pGraph );
+ Ivy_GraphUpdateNetworkSeq( p, pNode, pGraph, nGain );
+ if ( fCompl ) Dec_GraphComplement( pGraph );
+Rwt_ManAddTimeUpdate( pManRwt, clock() - clk );
+ }
+ }
+Rwt_ManAddTimeTotal( pManRwt, clock() - clkStart );
+ // print stats
+ if ( fVerbose )
+ Rwt_ManPrintStats( pManRwt );
+ // delete the managers
+ Rwt_ManStop( pManRwt );
+ p->pData = NULL;
+ // fix the levels
+ Ivy_ManResetLevels( p );
+// if ( Ivy_ManCheckFanoutNums(p) )
+// printf( "Ivy_ManRewritePre(): The check has failed.\n" );
+ // check
+ if ( !Ivy_ManCheck(p) )
+ printf( "Ivy_ManRewritePre(): The check has failed.\n" );
+ return 1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Performs rewriting for one node.]
+
+ Description [This procedure considers all the cuts computed for the node
+ and tries to rewrite each of them using the "forest" of different AIG
+ structures precomputed and stored in the RWR manager.
+ Determines the best rewriting and computes the gain in the number of AIG
+ nodes in the final network. In the end, p->vFanins contains information
+ about the best cut that can be used for rewriting, while p->pGraph gives
+ the decomposition dag (represented using decomposition graph data structure).
+ Returns gain in the number of nodes or -1 if node cannot be rewritten.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_NodeRewriteSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUseZeroCost )
+{
+ int fVeryVerbose = 0;
+ Dec_Graph_t * pGraph;
+ Ivy_Store_t * pStore;
+ Ivy_Cut_t * pCut;
+ Ivy_Obj_t * pFanin;//, * pFanout;
+ Vec_Ptr_t * vFanout;
+ unsigned uPhase, uTruthBest, uTruth;//, nNewClauses;
+ char * pPerm;
+ int nNodesSaved, nNodesSaveCur;
+ int i, c, GainCur, GainBest = -1;
+ int clk, clk2;//, clk3;
+
+ p->nNodesConsidered++;
+ // get the node's cuts
+clk = clock();
+ pStore = Ivy_CutComputeForNode( pMan, pNode, 5 );
+p->timeCut += clock() - clk;
+
+ // go through the cuts
+clk = clock();
+ vFanout = Vec_PtrAlloc( 100 );
+ for ( c = 1; c < pStore->nCuts; c++ )
+ {
+ pCut = pStore->pCuts + c;
+ // consider only 4-input cuts
+ if ( pCut->nSize != 4 )
+ continue;
+ // skip the cuts with buffers
+ for ( i = 0; i < (int)pCut->nSize; i++ )
+ if ( Ivy_ObjIsBuf( Ivy_ManObj(pMan, Ivy_LeafId(pCut->pArray[i])) ) )
+ break;
+ if ( i != pCut->nSize )
+ {
+ p->nCutsBad++;
+ continue;
+ }
+ p->nCutsGood++;
+ // get the fanin permutation
+clk2 = clock();
+ uTruth = 0xFFFF & Ivy_CutGetTruth( pMan, pNode, pCut->pArray, pCut->nSize ); // truth table
+p->timeTruth += clock() - clk2;
+ pPerm = p->pPerms4[ p->pPerms[uTruth] ];
+ uPhase = p->pPhases[uTruth];
+ // collect fanins with the corresponding permutation/phase
+ Vec_PtrClear( p->vFaninsCur );
+ Vec_PtrFill( p->vFaninsCur, (int)pCut->nSize, 0 );
+ for ( i = 0; i < (int)pCut->nSize; i++ )
+ {
+ pFanin = Ivy_ManObj( pMan, Ivy_LeafId( pCut->pArray[pPerm[i]] ) );
+ assert( Ivy_ObjIsNode(pFanin) || Ivy_ObjIsCi(pFanin) || Ivy_ObjIsConst1(pFanin) );
+ pFanin = Ivy_NotCond(pFanin, ((uPhase & (1<<i)) > 0) );
+ Vec_PtrWriteEntry( p->vFaninsCur, i, pFanin );
+ }
+clk2 = clock();
+ // mark the fanin boundary
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ Ivy_ObjRefsInc( Ivy_Regular(pFanin) );
+ // label MFFC with current ID
+ Ivy_ManIncrementTravId( pMan );
+ nNodesSaved = Ivy_ObjMffcLabel( pMan, pNode );
+ // label fanouts with the current ID
+// Ivy_ObjForEachFanout( pMan, pNode, vFanout, pFanout, i )
+// Ivy_ObjSetTravIdCurrent( pMan, pFanout );
+ // unmark the fanin boundary
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ Ivy_ObjRefsDec( Ivy_Regular(pFanin) );
+p->timeMffc += clock() - clk2;
+
+ // evaluate the cut
+clk2 = clock();
+ pGraph = Rwt_CutEvaluateSeq( pMan, p, pNode, pCut, pPerm, p->vFaninsCur, nNodesSaved, &GainCur, uTruth );
+p->timeEval += clock() - clk2;
+
+
+ // check if the cut is better than the current best one
+ if ( pGraph != NULL && GainBest < GainCur )
+ {
+ // save this form
+ nNodesSaveCur = nNodesSaved;
+ GainBest = GainCur;
+ p->pGraph = pGraph;
+ p->pCut = pCut;
+ p->pPerm = pPerm;
+ p->fCompl = ((uPhase & (1<<4)) > 0);
+ uTruthBest = uTruth;
+ // collect fanins in the
+ Vec_PtrClear( p->vFanins );
+ Vec_PtrForEachEntry( p->vFaninsCur, pFanin, i )
+ Vec_PtrPush( p->vFanins, pFanin );
+ }
+ }
+ Vec_PtrFree( vFanout );
+p->timeRes += clock() - clk;
+
+ if ( GainBest == -1 )
+ return -1;
+/*
+ {
+ Ivy_Cut_t * pCut = p->pCut;
+ printf( "Node %5d. Using cut : {", Ivy_ObjId(pNode) );
+ for ( i = 0; i < pCut->nSize; i++ )
+ printf( " %d(%d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
+ printf( " }\n" );
+ }
+*/
+
+//clk3 = clock();
+//nNewClauses = Ivy_CutTruthPrint( pMan, p->pCut, uTruth );
+//timeInv += clock() - clk;
+
+// nClauses += nNewClauses;
+// nMoves++;
+// if ( nNewClauses > 0 )
+// nMovesS++;
+
+ // copy the leaves
+ Ivy_GraphPrepare( p->pGraph, p->pCut, p->vFanins, p->pPerm );
+
+ p->nScores[p->pMap[uTruthBest]]++;
+ p->nNodesGained += GainBest;
+ if ( fUseZeroCost || GainBest > 0 )
+ p->nNodesRewritten++;
+
+/*
+ if ( GainBest > 0 )
+ {
+ Ivy_Cut_t * pCut = p->pCut;
+ printf( "Node %5d. Using cut : {", Ivy_ObjId(pNode) );
+ for ( i = 0; i < pCut->nSize; i++ )
+ printf( " %5d(%2d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
+ printf( " }\n" );
+ }
+*/
+
+ // report the progress
+ if ( fVeryVerbose && GainBest > 0 )
+ {
+ printf( "Node %6d : ", Ivy_ObjId(pNode) );
+ printf( "Fanins = %d. ", p->vFanins->nSize );
+ printf( "Save = %d. ", nNodesSaveCur );
+ printf( "Add = %d. ", nNodesSaveCur-GainBest );
+ printf( "GAIN = %d. ", GainBest );
+ printf( "Cone = %d. ", p->pGraph? Dec_GraphNodeNum(p->pGraph) : 0 );
+ printf( "Class = %d. ", p->pMap[uTruthBest] );
+ printf( "\n" );
+ }
+ return GainBest;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Evaluates the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Dec_Graph_t * Rwt_CutEvaluateSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pRoot, Ivy_Cut_t * pCut, char * pPerm, Vec_Ptr_t * vFaninsCur, int nNodesSaved, int * pGainBest, unsigned uTruth )
+{
+ Vec_Ptr_t * vSubgraphs;
+ Dec_Graph_t * pGraphBest, * pGraphCur;
+ Rwt_Node_t * pNode;
+ int nNodesAdded, GainBest, i;
+ // find the matching class of subgraphs
+ vSubgraphs = Vec_VecEntry( p->vClasses, p->pMap[uTruth] );
+ p->nSubgraphs += vSubgraphs->nSize;
+ // determine the best subgraph
+ GainBest = -1;
+ Vec_PtrForEachEntry( vSubgraphs, pNode, i )
+ {
+ // get the current graph
+ pGraphCur = (Dec_Graph_t *)pNode->pNext;
+
+// if ( pRoot->Id == 8648 )
+// Dec_GraphPrint( stdout, pGraphCur, NULL, NULL );
+ // copy the leaves
+// Vec_PtrForEachEntry( vFaninsCur, pFanin, k )
+// Dec_GraphNode(pGraphCur, k)->pFunc = pFanin;
+ Ivy_GraphPrepare( pGraphCur, pCut, vFaninsCur, pPerm );
+
+ // detect how many unlabeled nodes will be reused
+ nNodesAdded = Ivy_GraphToNetworkSeqCountSeq( pMan, pRoot, pGraphCur, nNodesSaved );
+ if ( nNodesAdded == -1 )
+ continue;
+ assert( nNodesSaved >= nNodesAdded );
+ // count the gain at this node
+ if ( GainBest < nNodesSaved - nNodesAdded )
+ {
+ GainBest = nNodesSaved - nNodesAdded;
+ pGraphBest = pGraphCur;
+ }
+ }
+ if ( GainBest == -1 )
+ return NULL;
+ *pGainBest = GainBest;
+ return pGraphBest;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_GraphPrepare( Dec_Graph_t * pGraph, Ivy_Cut_t * pCut, Vec_Ptr_t * vFanins, char * pPerm )
+{
+ Dec_Node_t * pNode, * pNode0, * pNode1;
+ int i;
+ assert( Dec_GraphLeaveNum(pGraph) == pCut->nSize );
+ assert( Vec_PtrSize(vFanins) == pCut->nSize );
+ // label the leaves with latch numbers
+ Dec_GraphForEachLeaf( pGraph, pNode, i )
+ {
+ pNode->pFunc = Vec_PtrEntry( vFanins, i );
+ pNode->nLat2 = Ivy_LeafLat( pCut->pArray[pPerm[i]] );
+ }
+ // propagate latches through the nodes
+ Dec_GraphForEachNode( pGraph, pNode, i )
+ {
+ // get the children of this node
+ pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
+ pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
+ // distribute the latches
+ pNode->nLat2 = IVY_MIN( pNode0->nLat2, pNode1->nLat2 );
+ pNode->nLat0 = pNode0->nLat2 - pNode->nLat2;
+ pNode->nLat1 = pNode1->nLat2 - pNode->nLat2;
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Counts the number of new nodes added when using this graph.]
+
+ Description [AIG nodes for the fanins should be assigned to pNode->pFunc
+ of the leaves of the graph before calling this procedure.
+ Returns -1 if the number of nodes and levels exceeded the given limit or
+ the number of levels exceeded the maximum allowed level.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_GraphToNetworkSeqCountSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax )
+{
+ Dec_Node_t * pNode, * pNode0, * pNode1;
+ Ivy_Obj_t * pAnd, * pAnd0, * pAnd1;
+ int i, k, Counter, fCompl;
+ // check for constant function or a literal
+ if ( Dec_GraphIsConst(pGraph) || Dec_GraphIsVar(pGraph) )
+ return 0;
+ // compute the AIG size after adding the internal nodes
+ Counter = 0;
+ Dec_GraphForEachNode( pGraph, pNode, i )
+ {
+ // get the children of this node
+ pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
+ pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
+ // get the AIG nodes corresponding to the children
+ pAnd0 = pNode0->pFunc;
+ pAnd1 = pNode1->pFunc;
+ // skip the latches
+ for ( k = 0; pAnd0 && k < (int)pNode->nLat0; k++ )
+ {
+ fCompl = Ivy_IsComplement(pAnd0);
+ pAnd0 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Regular(pAnd0), NULL, IVY_LATCH, IVY_INIT_DC) );
+ if ( pAnd0 )
+ pAnd0 = Ivy_NotCond( pAnd0, fCompl );
+ }
+ for ( k = 0; pAnd1 && k < (int)pNode->nLat1; k++ )
+ {
+ fCompl = Ivy_IsComplement(pAnd1);
+ pAnd1 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Regular(pAnd1), NULL, IVY_LATCH, IVY_INIT_DC) );
+ if ( pAnd1 )
+ pAnd1 = Ivy_NotCond( pAnd1, fCompl );
+ }
+ // get the new node
+ if ( pAnd0 && pAnd1 )
+ {
+ // if they are both present, find the resulting node
+ pAnd0 = Ivy_NotCond( pAnd0, pNode->eEdge0.fCompl );
+ pAnd1 = Ivy_NotCond( pAnd1, pNode->eEdge1.fCompl );
+ assert( !Ivy_ObjIsLatch(Ivy_Regular(pAnd0)) || !Ivy_ObjIsLatch(Ivy_Regular(pAnd1)) );
+ if ( Ivy_Regular(pAnd0) == Ivy_Regular(pAnd1) || Ivy_ObjIsConst1(Ivy_Regular(pAnd0)) || Ivy_ObjIsConst1(Ivy_Regular(pAnd1)) )
+ pAnd = Ivy_And( p, pAnd0, pAnd1 );
+ else
+ pAnd = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, pAnd0, pAnd1, IVY_AND, IVY_INIT_NONE) );
+ // return -1 if the node is the same as the original root
+ if ( Ivy_Regular(pAnd) == pRoot )
+ return -1;
+ }
+ else
+ pAnd = NULL;
+ // count the number of added nodes
+ if ( pAnd == NULL || Ivy_ObjIsTravIdCurrent(p, Ivy_Regular(pAnd)) )
+ {
+ if ( ++Counter > NodeMax )
+ return -1;
+ }
+ pNode->pFunc = pAnd;
+ }
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Transforms the decomposition graph into the AIG.]
+
+ Description [AIG nodes for the fanins should be assigned to pNode->pFunc
+ of the leaves of the graph before calling this procedure.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_GraphToNetworkSeq( Ivy_Man_t * p, Dec_Graph_t * pGraph )
+{
+ Ivy_Obj_t * pAnd0, * pAnd1;
+ Dec_Node_t * pNode;
+ int i, k;
+ // check for constant function
+ if ( Dec_GraphIsConst(pGraph) )
+ return Ivy_NotCond( Ivy_ManConst1(p), Dec_GraphIsComplement(pGraph) );
+ // check for a literal
+ if ( Dec_GraphIsVar(pGraph) )
+ {
+ // get the variable node
+ pNode = Dec_GraphVar(pGraph);
+ // add the remaining latches
+ for ( k = 0; k < (int)pNode->nLat2; k++ )
+ pNode->pFunc = Ivy_Latch( p, pNode->pFunc, IVY_INIT_DC );
+ return Ivy_NotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) );
+ }
+ // build the AIG nodes corresponding to the AND gates of the graph
+ Dec_GraphForEachNode( pGraph, pNode, i )
+ {
+ pAnd0 = Ivy_NotCond( Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl );
+ pAnd1 = Ivy_NotCond( Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl );
+ // add the latches
+ for ( k = 0; k < (int)pNode->nLat0; k++ )
+ pAnd0 = Ivy_Latch( p, pAnd0, IVY_INIT_DC );
+ for ( k = 0; k < (int)pNode->nLat1; k++ )
+ pAnd1 = Ivy_Latch( p, pAnd1, IVY_INIT_DC );
+ // create the node
+ pNode->pFunc = Ivy_And( p, pAnd0, pAnd1 );
+ }
+ // add the remaining latches
+ for ( k = 0; k < (int)pNode->nLat2; k++ )
+ pNode->pFunc = Ivy_Latch( p, pNode->pFunc, IVY_INIT_DC );
+ // complement the result if necessary
+ return Ivy_NotCond( pNode->pFunc, Dec_GraphIsComplement(pGraph) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Replaces MFFC of the node by the new factored form.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_GraphUpdateNetworkSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int nGain )
+{
+ Ivy_Obj_t * pRootNew;
+ int nNodesNew, nNodesOld;
+ nNodesOld = Ivy_ManNodeNum(p);
+ // create the new structure of nodes
+ pRootNew = Ivy_GraphToNetworkSeq( p, pGraph );
+ Ivy_ObjReplace( p, pRoot, pRootNew, 1, 0, 0 );
+ // compare the gains
+ nNodesNew = Ivy_ManNodeNum(p);
+ assert( nGain <= nNodesOld - nNodesNew );
+ // propagate the buffer
+ Ivy_ManPropagateBuffers( p, 0 );
+}
+
+
+
+
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_CutGetTruth_rec( Ivy_Man_t * p, int Leaf, int * pNums, int nNums )
+{
+ static unsigned uMasks[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
+ unsigned uTruth0, uTruth1;
+ Ivy_Obj_t * pObj;
+ int i;
+ for ( i = 0; i < nNums; i++ )
+ if ( Leaf == pNums[i] )
+ return uMasks[i];
+ pObj = Ivy_ManObj( p, Ivy_LeafId(Leaf) );
+ if ( Ivy_ObjIsLatch(pObj) )
+ {
+ assert( !Ivy_ObjFaninC0(pObj) );
+ Leaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pObj), Ivy_LeafLat(Leaf) + 1 );
+ return Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
+ }
+ assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj) );
+ Leaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pObj), Ivy_LeafLat(Leaf) );
+ uTruth0 = Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
+ if ( Ivy_ObjFaninC0(pObj) )
+ uTruth0 = ~uTruth0;
+ if ( Ivy_ObjIsBuf(pObj) )
+ return uTruth0;
+ Leaf = Ivy_LeafCreate( Ivy_ObjFaninId1(pObj), Ivy_LeafLat(Leaf) );
+ uTruth1 = Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
+ if ( Ivy_ObjFaninC1(pObj) )
+ uTruth1 = ~uTruth1;
+ return uTruth0 & uTruth1;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Computes the truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned Ivy_CutGetTruth( Ivy_Man_t * p, Ivy_Obj_t * pObj, int * pNums, int nNums )
+{
+ assert( Ivy_ObjIsNode(pObj) );
+ assert( nNums < 6 );
+ return Ivy_CutGetTruth_rec( p, Ivy_LeafCreate(pObj->Id, 0), pNums, nNums );
+}
+
+
+
+
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the cut can be constructed; 0 otherwise.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutPrescreen( Ivy_Cut_t * pCut, int Id0, int Id1 )
+{
+ int i;
+ if ( pCut->nSize < pCut->nSizeMax )
+ return 1;
+ for ( i = 0; i < pCut->nSize; i++ )
+ if ( pCut->pArray[i] == Id0 || pCut->pArray[i] == Id1 )
+ return 1;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives new cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutDeriveNew2( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
+{
+ unsigned uHash = 0;
+ int i, k;
+ assert( pCut->nSize > 0 );
+ assert( IdNew0 < IdNew1 );
+ for ( i = k = 0; i < pCut->nSize; i++ )
+ {
+ if ( pCut->pArray[i] == IdOld )
+ continue;
+ if ( IdNew0 >= 0 )
+ {
+ if ( IdNew0 <= pCut->pArray[i] )
+ {
+ if ( IdNew0 < pCut->pArray[i] )
+ {
+ if ( k == pCut->nSizeMax )
+ return 0;
+ pCutNew->pArray[ k++ ] = IdNew0;
+ uHash |= Ivy_CutHashValue( IdNew0 );
+ }
+ IdNew0 = -1;
+ }
+ }
+ if ( IdNew1 >= 0 )
+ {
+ if ( IdNew1 <= pCut->pArray[i] )
+ {
+ if ( IdNew1 < pCut->pArray[i] )
+ {
+ if ( k == pCut->nSizeMax )
+ return 0;
+ pCutNew->pArray[ k++ ] = IdNew1;
+ uHash |= Ivy_CutHashValue( IdNew1 );
+ }
+ IdNew1 = -1;
+ }
+ }
+ if ( k == pCut->nSizeMax )
+ return 0;
+ pCutNew->pArray[ k++ ] = pCut->pArray[i];
+ uHash |= Ivy_CutHashValue( pCut->pArray[i] );
+ }
+ if ( IdNew0 >= 0 )
+ {
+ if ( k == pCut->nSizeMax )
+ return 0;
+ pCutNew->pArray[ k++ ] = IdNew0;
+ uHash |= Ivy_CutHashValue( IdNew0 );
+ }
+ if ( IdNew1 >= 0 )
+ {
+ if ( k == pCut->nSizeMax )
+ return 0;
+ pCutNew->pArray[ k++ ] = IdNew1;
+ uHash |= Ivy_CutHashValue( IdNew1 );
+ }
+ pCutNew->nSize = k;
+ pCutNew->uHash = uHash;
+ assert( pCutNew->nSize <= pCut->nSizeMax );
+ for ( i = 1; i < pCutNew->nSize; i++ )
+ assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives new cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutDeriveNew( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
+{
+ unsigned uHash = 0;
+ int i, k;
+ assert( pCut->nSize > 0 );
+ assert( IdNew0 < IdNew1 );
+ for ( i = k = 0; i < pCut->nSize; i++ )
+ {
+ if ( pCut->pArray[i] == IdOld )
+ continue;
+ if ( IdNew0 <= pCut->pArray[i] )
+ {
+ if ( IdNew0 < pCut->pArray[i] )
+ {
+ pCutNew->pArray[ k++ ] = IdNew0;
+ uHash |= Ivy_CutHashValue( IdNew0 );
+ }
+ IdNew0 = 0x7FFFFFFF;
+ }
+ if ( IdNew1 <= pCut->pArray[i] )
+ {
+ if ( IdNew1 < pCut->pArray[i] )
+ {
+ pCutNew->pArray[ k++ ] = IdNew1;
+ uHash |= Ivy_CutHashValue( IdNew1 );
+ }
+ IdNew1 = 0x7FFFFFFF;
+ }
+ pCutNew->pArray[ k++ ] = pCut->pArray[i];
+ uHash |= Ivy_CutHashValue( pCut->pArray[i] );
+ }
+ if ( IdNew0 < 0x7FFFFFFF )
+ {
+ pCutNew->pArray[ k++ ] = IdNew0;
+ uHash |= Ivy_CutHashValue( IdNew0 );
+ }
+ if ( IdNew1 < 0x7FFFFFFF )
+ {
+ pCutNew->pArray[ k++ ] = IdNew1;
+ uHash |= Ivy_CutHashValue( IdNew1 );
+ }
+ pCutNew->nSize = k;
+ pCutNew->uHash = uHash;
+ assert( pCutNew->nSize <= pCut->nSizeMax );
+// for ( i = 1; i < pCutNew->nSize; i++ )
+// assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Find the hash value of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline unsigned Ivy_NodeCutHash( Ivy_Cut_t * pCut )
+{
+ int i;
+ pCut->uHash = 0;
+ for ( i = 0; i < pCut->nSize; i++ )
+ pCut->uHash |= (1 << (pCut->pArray[i] % 31));
+ return pCut->uHash;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Derives new cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutDeriveNew3( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
+{
+ int i, k;
+ assert( pCut->nSize > 0 );
+ assert( IdNew0 < IdNew1 );
+ for ( i = k = 0; i < pCut->nSize; i++ )
+ {
+ if ( pCut->pArray[i] == IdOld )
+ continue;
+ if ( IdNew0 <= pCut->pArray[i] )
+ {
+ if ( IdNew0 < pCut->pArray[i] )
+ pCutNew->pArray[ k++ ] = IdNew0;
+ IdNew0 = 0x7FFFFFFF;
+ }
+ if ( IdNew1 <= pCut->pArray[i] )
+ {
+ if ( IdNew1 < pCut->pArray[i] )
+ pCutNew->pArray[ k++ ] = IdNew1;
+ IdNew1 = 0x7FFFFFFF;
+ }
+ pCutNew->pArray[ k++ ] = pCut->pArray[i];
+ }
+ if ( IdNew0 < 0x7FFFFFFF )
+ pCutNew->pArray[ k++ ] = IdNew0;
+ if ( IdNew1 < 0x7FFFFFFF )
+ pCutNew->pArray[ k++ ] = IdNew1;
+ pCutNew->nSize = k;
+ assert( pCutNew->nSize <= pCut->nSizeMax );
+ Ivy_NodeCutHash( pCutNew );
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if pDom is contained in pCut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutCheckDominance( Ivy_Cut_t * pDom, Ivy_Cut_t * pCut )
+{
+ int i, k;
+ for ( i = 0; i < pDom->nSize; i++ )
+ {
+ assert( i==0 || pDom->pArray[i-1] < pDom->pArray[i] );
+ for ( k = 0; k < pCut->nSize; k++ )
+ if ( pDom->pArray[i] == pCut->pArray[k] )
+ break;
+ if ( k == pCut->nSize ) // node i in pDom is not contained in pCut
+ return 0;
+ }
+ // every node in pDom is contained in pCut
+ return 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Check if the cut exists.]
+
+ Description [Returns 1 if the cut exists.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_CutFindOrAddFilter( Ivy_Store_t * pCutStore, Ivy_Cut_t * pCutNew )
+{
+ Ivy_Cut_t * pCut;
+ int i, k;
+ assert( pCutNew->uHash );
+ // try to find the cut
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ {
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->nSize == 0 )
+ continue;
+ if ( pCut->nSize == pCutNew->nSize )
+ {
+ if ( pCut->uHash == pCutNew->uHash )
+ {
+ for ( k = 0; k < pCutNew->nSize; k++ )
+ if ( pCut->pArray[k] != pCutNew->pArray[k] )
+ break;
+ if ( k == pCutNew->nSize )
+ return 1;
+ }
+ continue;
+ }
+ if ( pCut->nSize < pCutNew->nSize )
+ {
+ // skip the non-contained cuts
+ if ( (pCut->uHash & pCutNew->uHash) != pCut->uHash )
+ continue;
+ // check containment seriously
+ if ( Ivy_CutCheckDominance( pCut, pCutNew ) )
+ return 1;
+ continue;
+ }
+ // check potential containment of other cut
+
+ // skip the non-contained cuts
+ if ( (pCut->uHash & pCutNew->uHash) != pCutNew->uHash )
+ continue;
+ // check containment seriously
+ if ( Ivy_CutCheckDominance( pCutNew, pCut ) )
+ {
+ // remove the current cut
+ pCut->nSize = 0;
+ }
+ }
+ assert( pCutStore->nCuts < pCutStore->nCutsMax );
+ // add the cut
+ pCut = pCutStore->pCuts + pCutStore->nCuts++;
+ *pCut = *pCutNew;
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compresses the cut representation.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_CutCompactAll( Ivy_Store_t * pCutStore )
+{
+ Ivy_Cut_t * pCut;
+ int i, k;
+ pCutStore->nCutsM = 0;
+ for ( i = k = 0; i < pCutStore->nCuts; i++ )
+ {
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->nSize == 0 )
+ continue;
+ if ( pCut->nSize < pCut->nSizeMax )
+ pCutStore->nCutsM++;
+ pCutStore->pCuts[k++] = *pCut;
+ }
+ pCutStore->nCuts = k;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Print the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_CutPrintForNode( Ivy_Cut_t * pCut )
+{
+ int i;
+ assert( pCut->nSize > 0 );
+ printf( "%d : {", pCut->nSize );
+ for ( i = 0; i < pCut->nSize; i++ )
+ printf( " %d", pCut->pArray[i] );
+ printf( " }\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_CutPrintForNodes( Ivy_Store_t * pCutStore )
+{
+ int i;
+ printf( "Node %d\n", pCutStore->pCuts[0].pArray[0] );
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ Ivy_CutPrintForNode( pCutStore->pCuts + i );
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+static inline int Ivy_CutReadLeaf( Ivy_Obj_t * pFanin )
+{
+ int nLats, iLeaf;
+ assert( !Ivy_IsComplement(pFanin) );
+ if ( !Ivy_ObjIsLatch(pFanin) )
+ return Ivy_LeafCreate( pFanin->Id, 0 );
+ iLeaf = Ivy_CutReadLeaf(Ivy_ObjFanin0(pFanin));
+ nLats = Ivy_LeafLat(iLeaf);
+ assert( nLats < IVY_LEAF_MASK );
+ return 1 + iLeaf;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Store_t * Ivy_CutComputeForNode( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves )
+{
+ static Ivy_Store_t CutStore, * pCutStore = &CutStore;
+ Ivy_Cut_t CutNew, * pCutNew = &CutNew, * pCut;
+ Ivy_Man_t * pMan = p;
+ Ivy_Obj_t * pLeaf;
+ int i, k, Temp, nLats, iLeaf0, iLeaf1;
+
+ assert( nLeaves <= IVY_CUT_INPUT );
+
+ // start the structure
+ pCutStore->nCuts = 0;
+ pCutStore->nCutsMax = IVY_CUT_LIMIT;
+ // start the trivial cut
+ pCutNew->uHash = 0;
+ pCutNew->nSize = 1;
+ pCutNew->nSizeMax = nLeaves;
+ pCutNew->pArray[0] = Ivy_LeafCreate( pObj->Id, 0 );
+ pCutNew->uHash = Ivy_CutHashValue( pCutNew->pArray[0] );
+ // add the trivial cut
+ pCutStore->pCuts[pCutStore->nCuts++] = *pCutNew;
+ assert( pCutStore->nCuts == 1 );
+
+ // explore the cuts
+ for ( i = 0; i < pCutStore->nCuts; i++ )
+ {
+ // expand this cut
+ pCut = pCutStore->pCuts + i;
+ if ( pCut->nSize == 0 )
+ continue;
+ for ( k = 0; k < pCut->nSize; k++ )
+ {
+ pLeaf = Ivy_ManObj( p, Ivy_LeafId(pCut->pArray[k]) );
+ if ( Ivy_ObjIsCi(pLeaf) || Ivy_ObjIsConst1(pLeaf) )
+ continue;
+ assert( Ivy_ObjIsNode(pLeaf) );
+ nLats = Ivy_LeafLat(pCut->pArray[k]);
+
+ // get the fanins fanins
+ iLeaf0 = Ivy_CutReadLeaf( Ivy_ObjFanin0(pLeaf) );
+ iLeaf1 = Ivy_CutReadLeaf( Ivy_ObjFanin1(pLeaf) );
+ assert( nLats + Ivy_LeafLat(iLeaf0) < IVY_LEAF_MASK && nLats + Ivy_LeafLat(iLeaf1) < IVY_LEAF_MASK );
+ iLeaf0 = nLats + iLeaf0;
+ iLeaf1 = nLats + iLeaf1;
+ if ( !Ivy_CutPrescreen( pCut, iLeaf0, iLeaf1 ) )
+ continue;
+ // the given cut exist
+ if ( iLeaf0 > iLeaf1 )
+ Temp = iLeaf0, iLeaf0 = iLeaf1, iLeaf1 = Temp;
+ // create the new cut
+ if ( !Ivy_CutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf0, iLeaf1 ) )
+ continue;
+ // add the cut
+ Ivy_CutFindOrAddFilter( pCutStore, pCutNew );
+ if ( pCutStore->nCuts == IVY_CUT_LIMIT )
+ break;
+ }
+ if ( pCutStore->nCuts == IVY_CUT_LIMIT )
+ break;
+ }
+ if ( pCutStore->nCuts == IVY_CUT_LIMIT )
+ pCutStore->fSatur = 1;
+ else
+ pCutStore->fSatur = 0;
+// printf( "%d ", pCutStore->nCuts );
+ Ivy_CutCompactAll( pCutStore );
+// printf( "%d \n", pCutStore->nCuts );
+// Ivy_CutPrintForNodes( pCutStore );
+ return pCutStore;
+}
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_CutComputeAll( Ivy_Man_t * p, int nInputs )
+{
+ Ivy_Store_t * pStore;
+ Ivy_Obj_t * pObj;
+ int i, nCutsTotal, nCutsTotalM, nNodeTotal, nNodeOver;
+ int clk = clock();
+ if ( nInputs > IVY_CUT_INPUT )
+ {
+ printf( "Cannot compute cuts for more than %d inputs.\n", IVY_CUT_INPUT );
+ return;
+ }
+ nNodeTotal = nNodeOver = 0;
+ nCutsTotal = nCutsTotalM = -Ivy_ManNodeNum(p);
+ Ivy_ManForEachObj( p, pObj, i )
+ {
+ if ( !Ivy_ObjIsNode(pObj) )
+ continue;
+ pStore = Ivy_CutComputeForNode( p, pObj, nInputs );
+ nCutsTotal += pStore->nCuts;
+ nCutsTotalM += pStore->nCutsM;
+ nNodeOver += pStore->fSatur;
+ nNodeTotal++;
+ }
+ printf( "All = %6d. Minus = %6d. Triv = %6d. Node = %6d. Satur = %6d. ",
+ nCutsTotal, nCutsTotalM, Ivy_ManPiNum(p) + Ivy_ManNodeNum(p), nNodeTotal, nNodeOver );
+ PRT( "Time", clock() - clk );
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyShow.c b/src/aig/ivy/ivyShow.c
new file mode 100644
index 00000000..cd726e43
--- /dev/null
+++ b/src/aig/ivy/ivyShow.c
@@ -0,0 +1,338 @@
+/**CFile****************************************************************
+
+ FileName [ivyShow.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Visualization of HAIG.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyShow.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+static void Ivy_WriteDotAig( Ivy_Man_t * pMan, char * pFileName, int fHaig, Vec_Ptr_t * vBold );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManShow( Ivy_Man_t * pMan, int fHaig, Vec_Ptr_t * vBold )
+{
+ extern void Abc_ShowFile( char * FileNameDot );
+ static Counter = 0;
+ char FileNameDot[200];
+ FILE * pFile;
+ // create the file name
+// Ivy_ShowGetFileName( pMan->pName, FileNameDot );
+ sprintf( FileNameDot, "temp%02d.dot", Counter++ );
+ // check that the file can be opened
+ if ( (pFile = fopen( FileNameDot, "w" )) == NULL )
+ {
+ fprintf( stdout, "Cannot open the intermediate file \"%s\".\n", FileNameDot );
+ return;
+ }
+ fclose( pFile );
+ // generate the file
+ Ivy_WriteDotAig( pMan, FileNameDot, fHaig, vBold );
+ // visualize the file
+ Abc_ShowFile( FileNameDot );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Writes the graph structure of AIG for DOT.]
+
+ Description [Useful for graph visualization using tools such as GraphViz:
+ http://www.graphviz.org/]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_WriteDotAig( Ivy_Man_t * pMan, char * pFileName, int fHaig, Vec_Ptr_t * vBold )
+{
+ FILE * pFile;
+ Ivy_Obj_t * pNode, * pTemp, * pPrev;
+ int LevelMax, Level, i;
+
+ if ( Ivy_ManNodeNum(pMan) > 200 )
+ {
+ fprintf( stdout, "Cannot visualize AIG with more than 200 nodes.\n" );
+ return;
+ }
+ if ( (pFile = fopen( pFileName, "w" )) == NULL )
+ {
+ fprintf( stdout, "Cannot open the intermediate file \"%s\".\n", pFileName );
+ return;
+ }
+
+ // mark the nodes
+ if ( vBold )
+ Vec_PtrForEachEntry( vBold, pNode, i )
+ pNode->fMarkB = 1;
+
+ // compute levels
+ LevelMax = 1 + Ivy_ManSetLevels( pMan, fHaig );
+
+ // write the DOT header
+ fprintf( pFile, "# %s\n", "AIG structure generated by IVY package" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "digraph AIG {\n" );
+ fprintf( pFile, "size = \"7.5,10\";\n" );
+// fprintf( pFile, "ranksep = 0.5;\n" );
+// fprintf( pFile, "nodesep = 0.5;\n" );
+ fprintf( pFile, "center = true;\n" );
+// fprintf( pFile, "orientation = landscape;\n" );
+// fprintf( pFile, "edge [fontsize = 10];\n" );
+// fprintf( pFile, "edge [dir = none];\n" );
+ fprintf( pFile, "edge [dir = back];\n" );
+ fprintf( pFile, "\n" );
+
+ // labels on the left of the picture
+ fprintf( pFile, "{\n" );
+ fprintf( pFile, " node [shape = plaintext];\n" );
+ fprintf( pFile, " edge [style = invis];\n" );
+ fprintf( pFile, " LevelTitle1 [label=\"\"];\n" );
+ fprintf( pFile, " LevelTitle2 [label=\"\"];\n" );
+ // generate node names with labels
+ for ( Level = LevelMax; Level >= 0; Level-- )
+ {
+ // the visible node name
+ fprintf( pFile, " Level%d", Level );
+ fprintf( pFile, " [label = " );
+ // label name
+ fprintf( pFile, "\"" );
+ fprintf( pFile, "\"" );
+ fprintf( pFile, "];\n" );
+ }
+
+ // genetate the sequence of visible/invisible nodes to mark levels
+ fprintf( pFile, " LevelTitle1 -> LevelTitle2 ->" );
+ for ( Level = LevelMax; Level >= 0; Level-- )
+ {
+ // the visible node name
+ fprintf( pFile, " Level%d", Level );
+ // the connector
+ if ( Level != 0 )
+ fprintf( pFile, " ->" );
+ else
+ fprintf( pFile, ";" );
+ }
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+
+ // generate title box on top
+ fprintf( pFile, "{\n" );
+ fprintf( pFile, " rank = same;\n" );
+ fprintf( pFile, " LevelTitle1;\n" );
+ fprintf( pFile, " title1 [shape=plaintext,\n" );
+ fprintf( pFile, " fontsize=20,\n" );
+ fprintf( pFile, " fontname = \"Times-Roman\",\n" );
+ fprintf( pFile, " label=\"" );
+ fprintf( pFile, "%s", "AIG structure visualized by ABC" );
+ fprintf( pFile, "\\n" );
+ fprintf( pFile, "Benchmark \\\"%s\\\". ", "aig" );
+ fprintf( pFile, "Time was %s. ", Extra_TimeStamp() );
+ fprintf( pFile, "\"\n" );
+ fprintf( pFile, " ];\n" );
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+
+ // generate statistics box
+ fprintf( pFile, "{\n" );
+ fprintf( pFile, " rank = same;\n" );
+ fprintf( pFile, " LevelTitle2;\n" );
+ fprintf( pFile, " title2 [shape=plaintext,\n" );
+ fprintf( pFile, " fontsize=18,\n" );
+ fprintf( pFile, " fontname = \"Times-Roman\",\n" );
+ fprintf( pFile, " label=\"" );
+ fprintf( pFile, "The set contains %d logic nodes and spans %d levels.", Ivy_ManNodeNum(pMan), LevelMax );
+ fprintf( pFile, "\\n" );
+ fprintf( pFile, "\"\n" );
+ fprintf( pFile, " ];\n" );
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+
+ // generate the COs
+ fprintf( pFile, "{\n" );
+ fprintf( pFile, " rank = same;\n" );
+ // the labeling node of this level
+ fprintf( pFile, " Level%d;\n", LevelMax );
+ // generate the CO nodes
+ Ivy_ManForEachCo( pMan, pNode, i )
+ {
+ if ( fHaig || pNode->pEquiv == NULL )
+ fprintf( pFile, " Node%d%s [label = \"%d%s\"", pNode->Id,
+ (Ivy_ObjIsLatch(pNode)? "_in":""), pNode->Id, (Ivy_ObjIsLatch(pNode)? "_in":"") );
+ else
+ fprintf( pFile, " Node%d%s [label = \"%d%s(%d%s)\"", pNode->Id,
+ (Ivy_ObjIsLatch(pNode)? "_in":""), pNode->Id, (Ivy_ObjIsLatch(pNode)? "_in":""),
+ Ivy_Regular(pNode->pEquiv)->Id, Ivy_IsComplement(pNode->pEquiv)? "\'":"" );
+ fprintf( pFile, ", shape = %s", (Ivy_ObjIsLatch(pNode)? "box":"invtriangle") );
+ fprintf( pFile, ", color = coral, fillcolor = coral" );
+ fprintf( pFile, "];\n" );
+ }
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+
+ // generate nodes of each rank
+ for ( Level = LevelMax - 1; Level > 0; Level-- )
+ {
+ fprintf( pFile, "{\n" );
+ fprintf( pFile, " rank = same;\n" );
+ // the labeling node of this level
+ fprintf( pFile, " Level%d;\n", Level );
+ Ivy_ManForEachObj( pMan, pNode, i )
+ {
+ if ( (int)pNode->Level != Level )
+ continue;
+ if ( fHaig || pNode->pEquiv == NULL )
+ fprintf( pFile, " Node%d [label = \"%d\"", pNode->Id, pNode->Id );
+ else
+ fprintf( pFile, " Node%d [label = \"%d(%d%s)\"", pNode->Id, pNode->Id,
+ Ivy_Regular(pNode->pEquiv)->Id, Ivy_IsComplement(pNode->pEquiv)? "\'":"" );
+ fprintf( pFile, ", shape = ellipse" );
+ if ( vBold && pNode->fMarkB )
+ fprintf( pFile, ", style = filled" );
+ fprintf( pFile, "];\n" );
+ }
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+ }
+
+ // generate the CI nodes
+ fprintf( pFile, "{\n" );
+ fprintf( pFile, " rank = same;\n" );
+ // the labeling node of this level
+ fprintf( pFile, " Level%d;\n", 0 );
+ // generate constant node
+ if ( Ivy_ObjRefs(Ivy_ManConst1(pMan)) > 0 )
+ {
+ pNode = Ivy_ManConst1(pMan);
+ // check if the costant node is present
+ fprintf( pFile, " Node%d [label = \"Const1\"", pNode->Id );
+ fprintf( pFile, ", shape = ellipse" );
+ fprintf( pFile, ", color = coral, fillcolor = coral" );
+ fprintf( pFile, "];\n" );
+ }
+ // generate the CI nodes
+ Ivy_ManForEachCi( pMan, pNode, i )
+ {
+ if ( fHaig || pNode->pEquiv == NULL )
+ fprintf( pFile, " Node%d%s [label = \"%d%s\"", pNode->Id,
+ (Ivy_ObjIsLatch(pNode)? "_out":""), pNode->Id, (Ivy_ObjIsLatch(pNode)? "_out":"") );
+ else
+ fprintf( pFile, " Node%d%s [label = \"%d%s(%d%s)\"", pNode->Id,
+ (Ivy_ObjIsLatch(pNode)? "_out":""), pNode->Id, (Ivy_ObjIsLatch(pNode)? "_out":""),
+ Ivy_Regular(pNode->pEquiv)->Id, Ivy_IsComplement(pNode->pEquiv)? "\'":"" );
+ fprintf( pFile, ", shape = %s", (Ivy_ObjIsLatch(pNode)? "box":"triangle") );
+ fprintf( pFile, ", color = coral, fillcolor = coral" );
+ fprintf( pFile, "];\n" );
+ }
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+
+ // generate invisible edges from the square down
+ fprintf( pFile, "title1 -> title2 [style = invis];\n" );
+ Ivy_ManForEachCo( pMan, pNode, i )
+ fprintf( pFile, "title2 -> Node%d%s [style = invis];\n", pNode->Id, (Ivy_ObjIsLatch(pNode)? "_in":"") );
+
+ // generate edges
+ Ivy_ManForEachObj( pMan, pNode, i )
+ {
+ if ( !Ivy_ObjIsNode(pNode) && !Ivy_ObjIsCo(pNode) && !Ivy_ObjIsBuf(pNode) )
+ continue;
+ // generate the edge from this node to the next
+ fprintf( pFile, "Node%d%s", pNode->Id, (Ivy_ObjIsLatch(pNode)? "_in":"") );
+ fprintf( pFile, " -> " );
+ fprintf( pFile, "Node%d%s", Ivy_ObjFaninId0(pNode), (Ivy_ObjIsLatch(Ivy_ObjFanin0(pNode))? "_out":"") );
+ fprintf( pFile, " [" );
+ fprintf( pFile, "style = %s", Ivy_ObjFaninC0(pNode)? "dotted" : "bold" );
+// if ( Ivy_NtkIsSeq(pNode->pMan) && Seq_ObjFaninL0(pNode) > 0 )
+// fprintf( pFile, ", label = \"%s\"", Seq_ObjFaninGetInitPrintable(pNode,0) );
+ fprintf( pFile, "]" );
+ fprintf( pFile, ";\n" );
+ if ( !Ivy_ObjIsNode(pNode) )
+ continue;
+ // generate the edge from this node to the next
+ fprintf( pFile, "Node%d", pNode->Id );
+ fprintf( pFile, " -> " );
+ fprintf( pFile, "Node%d%s", Ivy_ObjFaninId1(pNode), (Ivy_ObjIsLatch(Ivy_ObjFanin1(pNode))? "_out":"") );
+ fprintf( pFile, " [" );
+ fprintf( pFile, "style = %s", Ivy_ObjFaninC1(pNode)? "dotted" : "bold" );
+// if ( Ivy_NtkIsSeq(pNode->pMan) && Seq_ObjFaninL1(pNode) > 0 )
+// fprintf( pFile, ", label = \"%s\"", Seq_ObjFaninGetInitPrintable(pNode,1) );
+ fprintf( pFile, "]" );
+ fprintf( pFile, ";\n" );
+ // generate the edges between the equivalent nodes
+ if ( fHaig && pNode->pEquiv && Ivy_ObjRefs(pNode) > 0 )
+ {
+ pPrev = pNode;
+ for ( pTemp = pNode->pEquiv; pTemp != pNode; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ {
+ fprintf( pFile, "Node%d", pPrev->Id );
+ fprintf( pFile, " -> " );
+ fprintf( pFile, "Node%d", pTemp->Id );
+ fprintf( pFile, " [style = %s]", Ivy_IsComplement(pTemp->pEquiv)? "dotted" : "bold" );
+ fprintf( pFile, ";\n" );
+ pPrev = pTemp;
+ }
+ // connect the last node with the first
+ fprintf( pFile, "Node%d", pPrev->Id );
+ fprintf( pFile, " -> " );
+ fprintf( pFile, "Node%d", pNode->Id );
+ fprintf( pFile, " [style = %s]", Ivy_IsComplement(pPrev->pEquiv)? "dotted" : "bold" );
+ fprintf( pFile, ";\n" );
+ }
+ }
+
+ fprintf( pFile, "}" );
+ fprintf( pFile, "\n" );
+ fprintf( pFile, "\n" );
+ fclose( pFile );
+
+ // unmark nodes
+ if ( vBold )
+ Vec_PtrForEachEntry( vBold, pNode, i )
+ pNode->fMarkB = 0;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyTable.c b/src/aig/ivy/ivyTable.c
new file mode 100644
index 00000000..2ac0ae49
--- /dev/null
+++ b/src/aig/ivy/ivyTable.c
@@ -0,0 +1,301 @@
+/**CFile****************************************************************
+
+ FileName [ivyTable.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Structural hashing table.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006. ]
+
+ Revision [$Id: ivyTable.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+// hashing the node
+static unsigned Ivy_Hash( Ivy_Obj_t * pObj, int TableSize )
+{
+ unsigned Key = Ivy_ObjIsExor(pObj) * 1699;
+ Key ^= Ivy_ObjFaninId0(pObj) * 7937;
+ Key ^= Ivy_ObjFaninId1(pObj) * 2971;
+ Key ^= Ivy_ObjFaninC0(pObj) * 911;
+ Key ^= Ivy_ObjFaninC1(pObj) * 353;
+ Key ^= Ivy_ObjInit(pObj) * 911;
+ return Key % TableSize;
+}
+
+// returns the place where this node is stored (or should be stored)
+static int * Ivy_TableFind( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ int i;
+ assert( Ivy_ObjIsHash(pObj) );
+ for ( i = Ivy_Hash(pObj, p->nTableSize); p->pTable[i]; i = (i+1) % p->nTableSize )
+ if ( p->pTable[i] == pObj->Id )
+ break;
+ return p->pTable + i;
+}
+
+static void Ivy_TableResize( Ivy_Man_t * p );
+static unsigned int Cudd_PrimeAig( unsigned int p );
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Checks if node with the given attributes is in the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_TableLookup( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pEntry;
+ int i;
+ assert( !Ivy_IsComplement(pObj) );
+ if ( !Ivy_ObjIsHash(pObj) )
+ return NULL;
+ assert( Ivy_ObjIsLatch(pObj) || Ivy_ObjFaninId0(pObj) > 0 );
+ assert( Ivy_ObjFaninId1(pObj) == 0 || Ivy_ObjFaninId0(pObj) < Ivy_ObjFaninId1(pObj) );
+ if ( Ivy_ObjFanin0(pObj)->nRefs == 0 || (Ivy_ObjChild1(pObj) && Ivy_ObjFanin1(pObj)->nRefs == 0) )
+ return NULL;
+ for ( i = Ivy_Hash(pObj, p->nTableSize); p->pTable[i]; i = (i+1) % p->nTableSize )
+ {
+ pEntry = Ivy_ManObj( p, p->pTable[i] );
+ if ( Ivy_ObjChild0(pEntry) == Ivy_ObjChild0(pObj) &&
+ Ivy_ObjChild1(pEntry) == Ivy_ObjChild1(pObj) &&
+ Ivy_ObjInit(pEntry) == Ivy_ObjInit(pObj) &&
+ Ivy_ObjType(pEntry) == Ivy_ObjType(pObj) )
+ return pEntry;
+ }
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Adds the node to the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TableInsert( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ int * pPlace;
+ assert( !Ivy_IsComplement(pObj) );
+ if ( !Ivy_ObjIsHash(pObj) )
+ return;
+ if ( (pObj->Id & 63) == 0 )
+ {
+ if ( p->nTableSize < 2 * Ivy_ManHashObjNum(p) )
+ Ivy_TableResize( p );
+ }
+ pPlace = Ivy_TableFind( p, pObj );
+ assert( *pPlace == 0 );
+ *pPlace = pObj->Id;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Deletes the node from the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TableDelete( Ivy_Man_t * p, Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pEntry;
+ int i, * pPlace;
+ assert( !Ivy_IsComplement(pObj) );
+ if ( !Ivy_ObjIsHash(pObj) )
+ return;
+ pPlace = Ivy_TableFind( p, pObj );
+ assert( *pPlace == pObj->Id ); // node should be in the table
+ *pPlace = 0;
+ // rehash the adjacent entries
+ i = pPlace - p->pTable;
+ for ( i = (i+1) % p->nTableSize; p->pTable[i]; i = (i+1) % p->nTableSize )
+ {
+ pEntry = Ivy_ManObj( p, p->pTable[i] );
+ p->pTable[i] = 0;
+ Ivy_TableInsert( p, pEntry );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Updates the table to point to the new node.]
+
+ Description [If the old node (pObj) is in the table, updates the table
+ to point to an object with different ID (ObjIdNew). The table should
+ not contain an object with ObjIdNew (this is currently not checked).]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TableUpdate( Ivy_Man_t * p, Ivy_Obj_t * pObj, int ObjIdNew )
+{
+ int * pPlace;
+ assert( !Ivy_IsComplement(pObj) );
+ if ( !Ivy_ObjIsHash(pObj) )
+ return;
+ pPlace = Ivy_TableFind( p, pObj );
+ assert( *pPlace == pObj->Id ); // node should be in the table
+ *pPlace = ObjIdNew;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Count the number of nodes in the table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_TableCountEntries( Ivy_Man_t * p )
+{
+ int i, Counter = 0;
+ for ( i = 0; i < p->nTableSize; i++ )
+ Counter += (p->pTable[i] != 0);
+ return Counter;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Resizes the table.]
+
+ Description [Typically this procedure should not be called.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_TableResize( Ivy_Man_t * p )
+{
+ int * pTableOld, * pPlace;
+ int nTableSizeOld, Counter, nEntries, e, clk;
+clk = clock();
+ // save the old table
+ pTableOld = p->pTable;
+ nTableSizeOld = p->nTableSize;
+ // get the new table
+ p->nTableSize = Cudd_PrimeAig( 5 * Ivy_ManHashObjNum(p) );
+ p->pTable = ALLOC( int, p->nTableSize );
+ memset( p->pTable, 0, sizeof(int) * p->nTableSize );
+ // rehash the entries from the old table
+ Counter = 0;
+ for ( e = 0; e < nTableSizeOld; e++ )
+ {
+ if ( pTableOld[e] == 0 )
+ continue;
+ Counter++;
+ // get the place where this entry goes in the table table
+ pPlace = Ivy_TableFind( p, Ivy_ManObj(p, pTableOld[e]) );
+ assert( *pPlace == 0 ); // should not be in the table
+ *pPlace = pTableOld[e];
+ }
+ nEntries = Ivy_ManHashObjNum(p);
+// assert( Counter == nEntries );
+// printf( "Increasing the structural table size from %6d to %6d. ", nTableSizeOld, p->nTableSize );
+// PRT( "Time", clock() - clk );
+ // replace the table and the parameters
+ free( pTableOld );
+}
+
+/**Function********************************************************************
+
+ Synopsis [Profiles the hash table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+******************************************************************************/
+void Ivy_TableProfile( Ivy_Man_t * p )
+{
+ int i, Counter = 0;
+ for ( i = 0; i < p->nTableSize; i++ )
+ {
+ if ( p->pTable[i] )
+ Counter++;
+ else if ( Counter )
+ {
+ printf( "%d ", Counter );
+ Counter = 0;
+ }
+ }
+}
+
+/**Function********************************************************************
+
+ Synopsis [Returns the next prime &gt;= p.]
+
+ Description [Copied from CUDD, for stand-aloneness.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+unsigned int Cudd_PrimeAig( unsigned int p)
+{
+ int i,pn;
+
+ p--;
+ do {
+ p++;
+ if (p&1) {
+ pn = 1;
+ i = 3;
+ while ((unsigned) (i * i) <= p) {
+ if (p % i == 0) {
+ pn = 0;
+ break;
+ }
+ i += 2;
+ }
+ } else {
+ pn = 0;
+ }
+ } while (!pn);
+ return(p);
+
+} /* end of Cudd_Prime */
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivyUtil.c b/src/aig/ivy/ivyUtil.c
new file mode 100644
index 00000000..ab62a276
--- /dev/null
+++ b/src/aig/ivy/ivyUtil.c
@@ -0,0 +1,818 @@
+/**CFile****************************************************************
+
+ FileName [ivyUtil.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis [Various procedures.]
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivyUtil.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis [Increments the current traversal ID of the network.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManIncrementTravId( Ivy_Man_t * p )
+{
+ if ( p->nTravIds >= (1<<30)-1 - 1000 )
+ Ivy_ManCleanTravId( p );
+ p->nTravIds++;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Sets the DFS ordering of the nodes.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCleanTravId( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ p->nTravIds = 1;
+ Ivy_ManForEachObj( p, pObj, i )
+ pObj->TravId = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes truth table of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCollectCut_rec( Ivy_Man_t * p, Ivy_Obj_t * pNode, Vec_Int_t * vNodes )
+{
+ if ( pNode->fMarkA )
+ return;
+ pNode->fMarkA = 1;
+ assert( Ivy_ObjIsAnd(pNode) || Ivy_ObjIsExor(pNode) );
+ Ivy_ManCollectCut_rec( p, Ivy_ObjFanin0(pNode), vNodes );
+ Ivy_ManCollectCut_rec( p, Ivy_ObjFanin1(pNode), vNodes );
+ Vec_IntPush( vNodes, pNode->Id );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes truth table of the cut.]
+
+ Description [Does not modify the array of leaves. Uses array vTruth to store
+ temporary truth tables. The returned pointer should be used immediately.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCollectCut( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Int_t * vLeaves, Vec_Int_t * vNodes )
+{
+ int i, Leaf;
+ // collect and mark the leaves
+ Vec_IntClear( vNodes );
+ Vec_IntForEachEntry( vLeaves, Leaf, i )
+ {
+ Vec_IntPush( vNodes, Leaf );
+ Ivy_ManObj(p, Leaf)->fMarkA = 1;
+ }
+ // collect and mark the nodes
+ Ivy_ManCollectCut_rec( p, pRoot, vNodes );
+ // clean the nodes
+ Vec_IntForEachEntry( vNodes, Leaf, i )
+ Ivy_ManObj(p, Leaf)->fMarkA = 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the pointer to the truth table.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned * Ivy_ObjGetTruthStore( int ObjNum, Vec_Int_t * vTruth )
+{
+ return ((unsigned *)Vec_IntArray(vTruth)) + 8 * ObjNum;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes truth table of the cut.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManCutTruthOne( Ivy_Man_t * p, Ivy_Obj_t * pNode, Vec_Int_t * vTruth, int nWords )
+{
+ unsigned * pTruth, * pTruth0, * pTruth1;
+ int i;
+ pTruth = Ivy_ObjGetTruthStore( pNode->TravId, vTruth );
+ pTruth0 = Ivy_ObjGetTruthStore( Ivy_ObjFanin0(pNode)->TravId, vTruth );
+ pTruth1 = Ivy_ObjGetTruthStore( Ivy_ObjFanin1(pNode)->TravId, vTruth );
+ if ( Ivy_ObjIsExor(pNode) )
+ for ( i = 0; i < nWords; i++ )
+ pTruth[i] = pTruth0[i] ^ pTruth1[i];
+ else if ( !Ivy_ObjFaninC0(pNode) && !Ivy_ObjFaninC1(pNode) )
+ for ( i = 0; i < nWords; i++ )
+ pTruth[i] = pTruth0[i] & pTruth1[i];
+ else if ( !Ivy_ObjFaninC0(pNode) && Ivy_ObjFaninC1(pNode) )
+ for ( i = 0; i < nWords; i++ )
+ pTruth[i] = pTruth0[i] & ~pTruth1[i];
+ else if ( Ivy_ObjFaninC0(pNode) && !Ivy_ObjFaninC1(pNode) )
+ for ( i = 0; i < nWords; i++ )
+ pTruth[i] = ~pTruth0[i] & pTruth1[i];
+ else // if ( Ivy_ObjFaninC0(pNode) && Ivy_ObjFaninC1(pNode) )
+ for ( i = 0; i < nWords; i++ )
+ pTruth[i] = ~pTruth0[i] & ~pTruth1[i];
+}
+
+/**Function*************************************************************
+
+ Synopsis [Computes truth table of the cut.]
+
+ Description [Does not modify the array of leaves. Uses array vTruth to store
+ temporary truth tables. The returned pointer should be used immediately.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+unsigned * Ivy_ManCutTruth( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Vec_Int_t * vLeaves, Vec_Int_t * vNodes, Vec_Int_t * vTruth )
+{
+ static unsigned uTruths[8][8] = { // elementary truth tables
+ { 0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA,0xAAAAAAAA },
+ { 0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC,0xCCCCCCCC },
+ { 0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0,0xF0F0F0F0 },
+ { 0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00,0xFF00FF00 },
+ { 0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000,0xFFFF0000 },
+ { 0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF,0x00000000,0xFFFFFFFF },
+ { 0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF },
+ { 0x00000000,0x00000000,0x00000000,0x00000000,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF }
+ };
+ int i, Leaf;
+ // collect the cut
+ Ivy_ManCollectCut( p, pRoot, vLeaves, vNodes );
+ // set the node numbers
+ Vec_IntForEachEntry( vNodes, Leaf, i )
+ Ivy_ManObj(p, Leaf)->TravId = i;
+ // alloc enough memory
+ Vec_IntClear( vTruth );
+ Vec_IntGrow( vTruth, 8 * Vec_IntSize(vNodes) );
+ // set the elementary truth tables
+ Vec_IntForEachEntry( vLeaves, Leaf, i )
+ memcpy( Ivy_ObjGetTruthStore(i, vTruth), uTruths[i], 8 * sizeof(unsigned) );
+ // compute truths for other nodes
+ Vec_IntForEachEntryStart( vNodes, Leaf, i, Vec_IntSize(vLeaves) )
+ Ivy_ManCutTruthOne( p, Ivy_ManObj(p, Leaf), vTruth, 8 );
+ return Ivy_ObjGetTruthStore( pRoot->TravId, vTruth );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect the latches.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Vec_Int_t * Ivy_ManLatches( Ivy_Man_t * p )
+{
+ Vec_Int_t * vLatches;
+ Ivy_Obj_t * pObj;
+ int i;
+ vLatches = Vec_IntAlloc( Ivy_ManLatchNum(p) );
+ Ivy_ManForEachLatch( p, pObj, i )
+ Vec_IntPush( vLatches, pObj->Id );
+ return vLatches;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect the latches.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManLevels( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i, LevelMax = 0;
+ Ivy_ManForEachPo( p, pObj, i )
+ LevelMax = IVY_MAX( LevelMax, (int)Ivy_ObjFanin0(pObj)->Level );
+ return LevelMax;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect the latches.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ManResetLevels_rec( Ivy_Obj_t * pObj )
+{
+ if ( pObj->Level || Ivy_ObjIsCi(pObj) || Ivy_ObjIsConst1(pObj) )
+ return pObj->Level;
+ if ( Ivy_ObjIsBuf(pObj) )
+ return pObj->Level = Ivy_ManResetLevels_rec( Ivy_ObjFanin0(pObj) );
+ assert( Ivy_ObjIsNode(pObj) );
+ Ivy_ManResetLevels_rec( Ivy_ObjFanin0(pObj) );
+ Ivy_ManResetLevels_rec( Ivy_ObjFanin1(pObj) );
+ return pObj->Level = Ivy_ObjLevelNew( pObj );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Collect the latches.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManResetLevels( Ivy_Man_t * p )
+{
+ Ivy_Obj_t * pObj;
+ int i;
+ Ivy_ManForEachObj( p, pObj, i )
+ pObj->Level = 0;
+ Ivy_ManForEachCo( p, pObj, i )
+ Ivy_ManResetLevels_rec( Ivy_ObjFanin0(pObj) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [References/references the node and returns MFFC size.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ObjRefDeref( Ivy_Man_t * p, Ivy_Obj_t * pNode, int fReference, int fLabel )
+{
+ Ivy_Obj_t * pNode0, * pNode1;
+ int Counter;
+ // label visited nodes
+ if ( fLabel )
+ Ivy_ObjSetTravIdCurrent( p, pNode );
+ // skip the CI
+ if ( Ivy_ObjIsPi(pNode) )
+ return 0;
+ assert( Ivy_ObjIsNode(pNode) || Ivy_ObjIsBuf(pNode) || Ivy_ObjIsLatch(pNode) );
+ // process the internal node
+ pNode0 = Ivy_ObjFanin0(pNode);
+ pNode1 = Ivy_ObjFanin1(pNode);
+ Counter = Ivy_ObjIsNode(pNode);
+ if ( fReference )
+ {
+ if ( pNode0->nRefs++ == 0 )
+ Counter += Ivy_ObjRefDeref( p, pNode0, fReference, fLabel );
+ if ( pNode1 && pNode1->nRefs++ == 0 )
+ Counter += Ivy_ObjRefDeref( p, pNode1, fReference, fLabel );
+ }
+ else
+ {
+ assert( pNode0->nRefs > 0 );
+ assert( pNode1 == NULL || pNode1->nRefs > 0 );
+ if ( --pNode0->nRefs == 0 )
+ Counter += Ivy_ObjRefDeref( p, pNode0, fReference, fLabel );
+ if ( pNode1 && --pNode1->nRefs == 0 )
+ Counter += Ivy_ObjRefDeref( p, pNode1, fReference, fLabel );
+ }
+ return Counter;
+}
+
+
+/**Function*************************************************************
+
+ Synopsis [Labels MFFC with the current label.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ObjMffcLabel( Ivy_Man_t * p, Ivy_Obj_t * pNode )
+{
+ int nConeSize1, nConeSize2;
+ assert( !Ivy_IsComplement( pNode ) );
+ assert( Ivy_ObjIsNode( pNode ) );
+ nConeSize1 = Ivy_ObjRefDeref( p, pNode, 0, 1 ); // dereference
+ nConeSize2 = Ivy_ObjRefDeref( p, pNode, 1, 0 ); // reference
+ assert( nConeSize1 == nConeSize2 );
+ assert( nConeSize1 > 0 );
+ return nConeSize1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively updates fanout levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+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->fFanout );
+ assert( Ivy_ObjIsNode(pObj) );
+ vFanouts = Vec_PtrAlloc( 10 );
+ Ivy_ObjForEachFanout( p, pObj, vFanouts, pFanout, i )
+ {
+ if ( Ivy_ObjIsCo(pFanout) )
+ {
+// assert( (int)Ivy_ObjFanin0(pFanout)->Level <= p->nLevelMax );
+ continue;
+ }
+ LevelNew = Ivy_ObjLevelNew( pFanout );
+ if ( (int)pFanout->Level == LevelNew )
+ continue;
+ pFanout->Level = LevelNew;
+ Ivy_ObjUpdateLevel_rec( p, pFanout );
+ }
+ Vec_PtrFree( vFanouts );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Compute the new required level.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+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->fFanout && p->vRequired );
+ vFanouts = Vec_PtrAlloc( 10 );
+ Ivy_ObjForEachFanout( p, pObj, vFanouts, pFanout, i )
+ {
+ Required = Vec_IntEntry(p->vRequired, pFanout->Id);
+ LevelNew = IVY_MIN( LevelNew, Required );
+ }
+ Vec_PtrFree( vFanouts );
+ return LevelNew - 1;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recursively updates fanout levels.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjUpdateLevelR_rec( Ivy_Man_t * p, Ivy_Obj_t * pObj, int ReqNew )
+{
+ Ivy_Obj_t * pFanin;
+ if ( Ivy_ObjIsConst1(pObj) || Ivy_ObjIsCi(pObj) )
+ return;
+ assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj) );
+ // process the first fanin
+ pFanin = Ivy_ObjFanin0(pObj);
+ if ( Vec_IntEntry(p->vRequired, pFanin->Id) > ReqNew - 1 )
+ {
+ Vec_IntWriteEntry( p->vRequired, pFanin->Id, ReqNew - 1 );
+ Ivy_ObjUpdateLevelR_rec( p, pFanin, ReqNew - 1 );
+ }
+ if ( Ivy_ObjIsBuf(pObj) )
+ return;
+ // process the second fanin
+ pFanin = Ivy_ObjFanin1(pObj);
+ if ( Vec_IntEntry(p->vRequired, pFanin->Id) > ReqNew - 1 )
+ {
+ Vec_IntWriteEntry( p->vRequired, pFanin->Id, ReqNew - 1 );
+ Ivy_ObjUpdateLevelR_rec( p, pFanin, ReqNew - 1 );
+ }
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns 1 if the node is the root of MUX or EXOR/NEXOR.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_ObjIsMuxType( Ivy_Obj_t * pNode )
+{
+ Ivy_Obj_t * pNode0, * pNode1;
+ // check that the node is regular
+ assert( !Ivy_IsComplement(pNode) );
+ // if the node is not AND, this is not MUX
+ if ( !Ivy_ObjIsAnd(pNode) )
+ return 0;
+ // if the children are not complemented, this is not MUX
+ if ( !Ivy_ObjFaninC0(pNode) || !Ivy_ObjFaninC1(pNode) )
+ return 0;
+ // get children
+ pNode0 = Ivy_ObjFanin0(pNode);
+ pNode1 = Ivy_ObjFanin1(pNode);
+ // if the children are not ANDs, this is not MUX
+ if ( !Ivy_ObjIsAnd(pNode0) || !Ivy_ObjIsAnd(pNode1) )
+ return 0;
+ // otherwise the node is MUX iff it has a pair of equal grandchildren
+ return (Ivy_ObjFaninId0(pNode0) == Ivy_ObjFaninId0(pNode1) && (Ivy_ObjFaninC0(pNode0) ^ Ivy_ObjFaninC0(pNode1))) ||
+ (Ivy_ObjFaninId0(pNode0) == Ivy_ObjFaninId1(pNode1) && (Ivy_ObjFaninC0(pNode0) ^ Ivy_ObjFaninC1(pNode1))) ||
+ (Ivy_ObjFaninId1(pNode0) == Ivy_ObjFaninId0(pNode1) && (Ivy_ObjFaninC1(pNode0) ^ Ivy_ObjFaninC0(pNode1))) ||
+ (Ivy_ObjFaninId1(pNode0) == Ivy_ObjFaninId1(pNode1) && (Ivy_ObjFaninC1(pNode0) ^ Ivy_ObjFaninC1(pNode1)));
+}
+
+/**Function*************************************************************
+
+ Synopsis [Recognizes what nodes are control and data inputs of a MUX.]
+
+ Description [If the node is a MUX, returns the control variable C.
+ Assigns nodes T and E to be the then and else variables of the MUX.
+ Node C is never complemented. Nodes T and E can be complemented.
+ This function also recognizes EXOR/NEXOR gates as MUXes.]
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ObjRecognizeMux( Ivy_Obj_t * pNode, Ivy_Obj_t ** ppNodeT, Ivy_Obj_t ** ppNodeE )
+{
+ Ivy_Obj_t * pNode0, * pNode1;
+ assert( !Ivy_IsComplement(pNode) );
+ assert( Ivy_ObjIsMuxType(pNode) );
+ // get children
+ pNode0 = Ivy_ObjFanin0(pNode);
+ pNode1 = Ivy_ObjFanin1(pNode);
+ // find the control variable
+// if ( pNode1->p1 == Fraig_Not(pNode2->p1) )
+ if ( Ivy_ObjFaninId0(pNode0) == Ivy_ObjFaninId0(pNode1) && (Ivy_ObjFaninC0(pNode0) ^ Ivy_ObjFaninC0(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p1) )
+ if ( Ivy_ObjFaninC0(pNode0) )
+ { // pNode2->p1 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild1(pNode1));//pNode2->p2);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild1(pNode0));//pNode1->p2);
+ return Ivy_ObjChild0(pNode1);//pNode2->p1;
+ }
+ else
+ { // pNode1->p1 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild1(pNode0));//pNode1->p2);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild1(pNode1));//pNode2->p2);
+ return Ivy_ObjChild0(pNode0);//pNode1->p1;
+ }
+ }
+// else if ( pNode1->p1 == Fraig_Not(pNode2->p2) )
+ else if ( Ivy_ObjFaninId0(pNode0) == Ivy_ObjFaninId1(pNode1) && (Ivy_ObjFaninC0(pNode0) ^ Ivy_ObjFaninC1(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p1) )
+ if ( Ivy_ObjFaninC0(pNode0) )
+ { // pNode2->p2 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild0(pNode1));//pNode2->p1);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild1(pNode0));//pNode1->p2);
+ return Ivy_ObjChild1(pNode1);//pNode2->p2;
+ }
+ else
+ { // pNode1->p1 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild1(pNode0));//pNode1->p2);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild0(pNode1));//pNode2->p1);
+ return Ivy_ObjChild0(pNode0);//pNode1->p1;
+ }
+ }
+// else if ( pNode1->p2 == Fraig_Not(pNode2->p1) )
+ else if ( Ivy_ObjFaninId1(pNode0) == Ivy_ObjFaninId0(pNode1) && (Ivy_ObjFaninC1(pNode0) ^ Ivy_ObjFaninC0(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p2) )
+ if ( Ivy_ObjFaninC1(pNode0) )
+ { // pNode2->p1 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild1(pNode1));//pNode2->p2);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild0(pNode0));//pNode1->p1);
+ return Ivy_ObjChild0(pNode1);//pNode2->p1;
+ }
+ else
+ { // pNode1->p2 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild0(pNode0));//pNode1->p1);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild1(pNode1));//pNode2->p2);
+ return Ivy_ObjChild1(pNode0);//pNode1->p2;
+ }
+ }
+// else if ( pNode1->p2 == Fraig_Not(pNode2->p2) )
+ else if ( Ivy_ObjFaninId1(pNode0) == Ivy_ObjFaninId1(pNode1) && (Ivy_ObjFaninC1(pNode0) ^ Ivy_ObjFaninC1(pNode1)) )
+ {
+// if ( Fraig_IsComplement(pNode1->p2) )
+ if ( Ivy_ObjFaninC1(pNode0) )
+ { // pNode2->p2 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild0(pNode1));//pNode2->p1);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild0(pNode0));//pNode1->p1);
+ return Ivy_ObjChild1(pNode1);//pNode2->p2;
+ }
+ else
+ { // pNode1->p2 is positive phase of C
+ *ppNodeT = Ivy_Not(Ivy_ObjChild0(pNode0));//pNode1->p1);
+ *ppNodeE = Ivy_Not(Ivy_ObjChild0(pNode1));//pNode2->p1);
+ return Ivy_ObjChild1(pNode0);//pNode1->p2;
+ }
+ }
+ assert( 0 ); // this is not MUX
+ return NULL;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Returns the real fanin.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+Ivy_Obj_t * Ivy_ObjReal( Ivy_Obj_t * pObj )
+{
+ Ivy_Obj_t * pFanin;
+ if ( pObj == NULL || !Ivy_ObjIsBuf( Ivy_Regular(pObj) ) )
+ return pObj;
+ pFanin = Ivy_ObjReal( Ivy_ObjChild0(Ivy_Regular(pObj)) );
+ return Ivy_NotCond( pFanin, Ivy_IsComplement(pObj) );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints node in HAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ObjPrintVerbose( Ivy_Man_t * p, Ivy_Obj_t * pObj, int fHaig )
+{
+ Ivy_Obj_t * pTemp;
+ int fShowFanouts = 0;
+ assert( !Ivy_IsComplement(pObj) );
+ printf( "Node %5d : ", Ivy_ObjId(pObj) );
+ if ( Ivy_ObjIsConst1(pObj) )
+ printf( "constant 1" );
+ else if ( Ivy_ObjIsPi(pObj) )
+ printf( "PI" );
+ else if ( Ivy_ObjIsPo(pObj) )
+ printf( "PO" );
+ else if ( Ivy_ObjIsLatch(pObj) )
+ printf( "latch (%d%s)", Ivy_ObjFanin0(pObj)->Id, (Ivy_ObjFaninC0(pObj)? "\'" : " ") );
+ else if ( Ivy_ObjIsBuf(pObj) )
+ printf( "buffer (%d%s)", Ivy_ObjFanin0(pObj)->Id, (Ivy_ObjFaninC0(pObj)? "\'" : " ") );
+ else
+ printf( "AND( %5d%s, %5d%s )",
+ Ivy_ObjFanin0(pObj)->Id, (Ivy_ObjFaninC0(pObj)? "\'" : " "),
+ Ivy_ObjFanin1(pObj)->Id, (Ivy_ObjFaninC1(pObj)? "\'" : " ") );
+ printf( " (refs = %3d)", Ivy_ObjRefs(pObj) );
+ if ( fShowFanouts )
+ {
+ Vec_Ptr_t * vFanouts;
+ Ivy_Obj_t * pFanout;
+ int i;
+ vFanouts = Vec_PtrAlloc( 10 );
+ printf( "\nFanouts:\n" );
+ Ivy_ObjForEachFanout( p, pObj, vFanouts, pFanout, i )
+ {
+ printf( " " );
+ printf( "Node %5d : ", Ivy_ObjId(pFanout) );
+ if ( Ivy_ObjIsPo(pFanout) )
+ printf( "PO" );
+ else if ( Ivy_ObjIsLatch(pFanout) )
+ printf( "latch (%d%s)", Ivy_ObjFanin0(pFanout)->Id, (Ivy_ObjFaninC0(pFanout)? "\'" : " ") );
+ else if ( Ivy_ObjIsBuf(pFanout) )
+ printf( "buffer (%d%s)", Ivy_ObjFanin0(pFanout)->Id, (Ivy_ObjFaninC0(pFanout)? "\'" : " ") );
+ else
+ printf( "AND( %5d%s, %5d%s )",
+ Ivy_ObjFanin0(pFanout)->Id, (Ivy_ObjFaninC0(pFanout)? "\'" : " "),
+ Ivy_ObjFanin1(pFanout)->Id, (Ivy_ObjFaninC1(pFanout)? "\'" : " ") );
+ printf( "\n" );
+ }
+ Vec_PtrFree( vFanouts );
+ return;
+ }
+ if ( !fHaig )
+ {
+ if ( pObj->pEquiv == NULL )
+ printf( " HAIG node not given" );
+ else
+ printf( " HAIG node = %d%s", Ivy_Regular(pObj->pEquiv)->Id, (Ivy_IsComplement(pObj->pEquiv)? "\'" : " ") );
+ return;
+ }
+ if ( pObj->pEquiv == NULL )
+ return;
+ // there are choices
+ if ( Ivy_ObjRefs(pObj) > 0 )
+ {
+ // print equivalence class
+ printf( " { %5d ", pObj->Id );
+ assert( !Ivy_IsComplement(pObj->pEquiv) );
+ for ( pTemp = pObj->pEquiv; pTemp != pObj; pTemp = Ivy_Regular(pTemp->pEquiv) )
+ printf( " %5d%s", pTemp->Id, (Ivy_IsComplement(pTemp->pEquiv)? "\'" : " ") );
+ printf( " }" );
+ return;
+ }
+ // this is a secondary node
+ for ( pTemp = Ivy_Regular(pObj->pEquiv); Ivy_ObjRefs(pTemp) == 0; pTemp = Ivy_Regular(pTemp->pEquiv) );
+ assert( Ivy_ObjRefs(pTemp) > 0 );
+ printf( " class of %d", pTemp->Id );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Prints node in HAIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+void Ivy_ManPrintVerbose( Ivy_Man_t * p, int fHaig )
+{
+ Vec_Int_t * vNodes;
+ Ivy_Obj_t * pObj;
+ int i;
+ printf( "PIs: " );
+ Ivy_ManForEachPi( p, pObj, i )
+ printf( " %d", pObj->Id );
+ printf( "\n" );
+ printf( "POs: " );
+ Ivy_ManForEachPo( p, pObj, i )
+ printf( " %d", pObj->Id );
+ printf( "\n" );
+ printf( "Latches: " );
+ Ivy_ManForEachLatch( p, pObj, i )
+ printf( " %d=%d%s", pObj->Id, Ivy_ObjFanin0(pObj)->Id, (Ivy_ObjFaninC0(pObj)? "\'" : " ") );
+ printf( "\n" );
+ vNodes = Ivy_ManDfsSeq( p, NULL );
+ Ivy_ManForEachNodeVec( p, vNodes, pObj, i )
+ Ivy_ObjPrintVerbose( p, pObj, fHaig ), printf( "\n" );
+ printf( "\n" );
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs incremental rewriting of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_CutTruthPrint2( Ivy_Man_t * p, Ivy_Cut_t * pCut, unsigned uTruth )
+{
+ int i;
+ printf( "Trying cut : {" );
+ for ( i = 0; i < pCut->nSize; i++ )
+ printf( " %6d(%d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
+ printf( " } " );
+ Extra_PrintBinary( stdout, &uTruth, 16 ); printf( "\n" );
+ return 0;
+}
+
+/**Function*************************************************************
+
+ Synopsis [Performs incremental rewriting of the AIG.]
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+int Ivy_CutTruthPrint( Ivy_Man_t * p, Ivy_Cut_t * pCut, unsigned uTruth )
+{
+ Vec_Ptr_t * vArray;
+ Ivy_Obj_t * pObj, * pFanout;
+ int nLatches = 0;
+ int nPresent = 0;
+ int i, k;
+ int fVerbose = 0;
+
+ if ( fVerbose )
+ printf( "Trying cut : {" );
+ for ( i = 0; i < pCut->nSize; i++ )
+ {
+ if ( fVerbose )
+ printf( " %6d(%d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
+ nLatches += Ivy_LeafLat(pCut->pArray[i]);
+ }
+ if ( fVerbose )
+ printf( " } " );
+ if ( fVerbose )
+ printf( "Latches = %d. ", nLatches );
+
+ // check if there are latches on the fanout edges
+ vArray = Vec_PtrAlloc( 100 );
+ for ( i = 0; i < pCut->nSize; i++ )
+ {
+ pObj = Ivy_ManObj( p, Ivy_LeafId(pCut->pArray[i]) );
+ Ivy_ObjForEachFanout( p, pObj, vArray, pFanout, k )
+ {
+ if ( Ivy_ObjIsLatch(pFanout) )
+ {
+ nPresent++;
+ break;
+ }
+ }
+ }
+ Vec_PtrSize( vArray );
+ if ( fVerbose )
+ {
+ printf( "Present = %d. ", nPresent );
+ if ( nLatches > nPresent )
+ printf( "Clauses = %d. ", 2*(nLatches - nPresent) );
+ printf( "\n" );
+ }
+ return ( nLatches > nPresent ) ? 2*(nLatches - nPresent) : 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/ivy_.c b/src/aig/ivy/ivy_.c
new file mode 100644
index 00000000..65689689
--- /dev/null
+++ b/src/aig/ivy/ivy_.c
@@ -0,0 +1,48 @@
+/**CFile****************************************************************
+
+ FileName [ivy_.c]
+
+ SystemName [ABC: Logic synthesis and verification system.]
+
+ PackageName [And-Inverter Graph package.]
+
+ Synopsis []
+
+ Author [Alan Mishchenko]
+
+ Affiliation [UC Berkeley]
+
+ Date [Ver. 1.0. Started - May 11, 2006.]
+
+ Revision [$Id: ivy_.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
+
+***********************************************************************/
+
+#include "ivy.h"
+
+////////////////////////////////////////////////////////////////////////
+/// DECLARATIONS ///
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+/// FUNCTION DEFINITIONS ///
+////////////////////////////////////////////////////////////////////////
+
+/**Function*************************************************************
+
+ Synopsis []
+
+ Description []
+
+ SideEffects []
+
+ SeeAlso []
+
+***********************************************************************/
+
+
+////////////////////////////////////////////////////////////////////////
+/// END OF FILE ///
+////////////////////////////////////////////////////////////////////////
+
+
diff --git a/src/aig/ivy/module.make b/src/aig/ivy/module.make
new file mode 100644
index 00000000..daef43df
--- /dev/null
+++ b/src/aig/ivy/module.make
@@ -0,0 +1,22 @@
+SRC += src/aig/ivy/ivyBalance.c \
+ src/aig/ivy/ivyCanon.c \
+ src/aig/ivy/ivyCheck.c \
+ src/aig/ivy/ivyCut.c \
+ src/aig/ivy/ivyCutTrav.c \
+ src/aig/ivy/ivyDfs.c \
+ src/aig/ivy/ivyDsd.c \
+ src/aig/ivy/ivyFanout.c \
+ src/aig/ivy/ivyFastMap.c \
+ src/aig/ivy/ivyFraig.c \
+ src/aig/ivy/ivyHaig.c \
+ src/aig/ivy/ivyMan.c \
+ src/aig/ivy/ivyMem.c \
+ src/aig/ivy/ivyMulti.c \
+ src/aig/ivy/ivyObj.c \
+ src/aig/ivy/ivyOper.c \
+ src/aig/ivy/ivyResyn.c \
+ src/aig/ivy/ivyRwr.c \
+ src/aig/ivy/ivySeq.c \
+ src/aig/ivy/ivyShow.c \
+ src/aig/ivy/ivyTable.c \
+ src/aig/ivy/ivyUtil.c