1 /**CFile****************************************************************
2 
3   FileName    [ivySeq.c]
4 
5   SystemName  [ABC: Logic synthesis and verification system.]
6 
7   PackageName [And-Inverter Graph package.]
8 
9   Synopsis    []
10 
11   Author      [Alan Mishchenko]
12 
13   Affiliation [UC Berkeley]
14 
15   Date        [Ver. 1.0. Started - May 11, 2006.]
16 
17   Revision    [$Id: ivySeq.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
18 
19 ***********************************************************************/
20 
21 #include "ivy.h"
22 #include "bool/deco/deco.h"
23 #include "opt/rwt/rwt.h"
24 
25 ABC_NAMESPACE_IMPL_START
26 
27 
28 ////////////////////////////////////////////////////////////////////////
29 ///                        DECLARATIONS                              ///
30 ////////////////////////////////////////////////////////////////////////
31 
32 static int Ivy_NodeRewriteSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUseZeroCost );
33 static void Ivy_GraphPrepare( Dec_Graph_t * pGraph, Ivy_Cut_t * pCut, Vec_Ptr_t * vFanins, char * pPerm );
34 static unsigned Ivy_CutGetTruth( Ivy_Man_t * p, Ivy_Obj_t * pObj, int * pNums, int nNums );
35 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 );
36 static int Ivy_GraphToNetworkSeqCountSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax );
37 static Ivy_Obj_t * Ivy_GraphToNetworkSeq( Ivy_Man_t * p, Dec_Graph_t * pGraph );
38 static void Ivy_GraphUpdateNetworkSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int nGain );
39 static Ivy_Store_t * Ivy_CutComputeForNode( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves );
40 
Ivy_CutHashValue(int NodeId)41 static inline int Ivy_CutHashValue( int NodeId )  { return 1 << (NodeId % 31); }
42 
43 ////////////////////////////////////////////////////////////////////////
44 ///                     FUNCTION DEFINITIONS                         ///
45 ////////////////////////////////////////////////////////////////////////
46 
47 //int nMoves;
48 //int nMovesS;
49 //int nClauses;
50 //int timeInv;
51 
52 /**Function*************************************************************
53 
54   Synopsis    [Performs incremental rewriting of the AIG.]
55 
56   Description []
57 
58   SideEffects []
59 
60   SeeAlso     []
61 
62 ***********************************************************************/
Ivy_ManRewriteSeq(Ivy_Man_t * p,int fUseZeroCost,int fVerbose)63 int Ivy_ManRewriteSeq( Ivy_Man_t * p, int fUseZeroCost, int fVerbose )
64 {
65     Rwt_Man_t * pManRwt;
66     Ivy_Obj_t * pNode;
67     int i, nNodes, nGain;
68     abctime clk, clkStart = Abc_Clock();
69 
70     // set the DC latch values
71     Ivy_ManForEachLatch( p, pNode, i )
72         pNode->Init = IVY_INIT_DC;
73     // start the rewriting manager
74     pManRwt = Rwt_ManStart( 0 );
75     p->pData = pManRwt;
76     if ( pManRwt == NULL )
77         return 0;
78     // create fanouts
79     if ( p->fFanout == 0 )
80         Ivy_ManStartFanout( p );
81     // resynthesize each node once
82     nNodes = Ivy_ManObjIdMax(p);
83     Ivy_ManForEachNode( p, pNode, i )
84     {
85         assert( !Ivy_ObjIsBuf(pNode) );
86         assert( !Ivy_ObjIsBuf(Ivy_ObjFanin0(pNode)) );
87         assert( !Ivy_ObjIsBuf(Ivy_ObjFanin1(pNode)) );
88         // fix the fanin buffer problem
89 //        Ivy_NodeFixBufferFanins( p, pNode );
90 //        if ( Ivy_ObjIsBuf(pNode) )
91 //            continue;
92         // stop if all nodes have been tried once
93         if ( i > nNodes )
94             break;
95         // for each cut, try to resynthesize it
96         nGain = Ivy_NodeRewriteSeq( p, pManRwt, pNode, fUseZeroCost );
97         if ( nGain > 0 || (nGain == 0 && fUseZeroCost) )
98         {
99             Dec_Graph_t * pGraph = (Dec_Graph_t *)Rwt_ManReadDecs(pManRwt);
100             int fCompl           = Rwt_ManReadCompl(pManRwt);
101             // complement the FF if needed
102 clk = Abc_Clock();
103             if ( fCompl ) Dec_GraphComplement( pGraph );
104             Ivy_GraphUpdateNetworkSeq( p, pNode, pGraph, nGain );
105             if ( fCompl ) Dec_GraphComplement( pGraph );
106 Rwt_ManAddTimeUpdate( pManRwt, Abc_Clock() - clk );
107         }
108     }
109 Rwt_ManAddTimeTotal( pManRwt, Abc_Clock() - clkStart );
110     // print stats
111     if ( fVerbose )
112         Rwt_ManPrintStats( pManRwt );
113     // delete the managers
114     Rwt_ManStop( pManRwt );
115     p->pData = NULL;
116     // fix the levels
117     Ivy_ManResetLevels( p );
118 //    if ( Ivy_ManCheckFanoutNums(p) )
119 //        printf( "Ivy_ManRewritePre(): The check has failed.\n" );
120     // check
121     if ( !Ivy_ManCheck(p) )
122         printf( "Ivy_ManRewritePre(): The check has failed.\n" );
123     return 1;
124 }
125 
126 
127 /**Function*************************************************************
128 
129   Synopsis    [Performs rewriting for one node.]
130 
131   Description [This procedure considers all the cuts computed for the node
132   and tries to rewrite each of them using the "forest" of different AIG
133   structures precomputed and stored in the RWR manager.
134   Determines the best rewriting and computes the gain in the number of AIG
135   nodes in the final network. In the end, p->vFanins contains information
136   about the best cut that can be used for rewriting, while p->pGraph gives
137   the decomposition dag (represented using decomposition graph data structure).
138   Returns gain in the number of nodes or -1 if node cannot be rewritten.]
139 
140   SideEffects []
141 
142   SeeAlso     []
143 
144 ***********************************************************************/
Ivy_NodeRewriteSeq(Ivy_Man_t * pMan,Rwt_Man_t * p,Ivy_Obj_t * pNode,int fUseZeroCost)145 int Ivy_NodeRewriteSeq( Ivy_Man_t * pMan, Rwt_Man_t * p, Ivy_Obj_t * pNode, int fUseZeroCost )
146 {
147     int fVeryVerbose = 0;
148     Dec_Graph_t * pGraph;
149     Ivy_Store_t * pStore;
150     Ivy_Cut_t * pCut;
151     Ivy_Obj_t * pFanin;//, * pFanout;
152     Vec_Ptr_t * vFanout;
153     unsigned uPhase;
154     unsigned uTruthBest = 0; // Suppress "might be used uninitialized"
155     unsigned uTruth;//, nNewClauses;
156     char * pPerm;
157     int nNodesSaved;
158     int nNodesSaveCur = -1; // Suppress "might be used uninitialized"
159     int i, c, GainCur = -1, GainBest = -1;
160     abctime clk, clk2;//, clk3;
161 
162     p->nNodesConsidered++;
163     // get the node's cuts
164 clk = Abc_Clock();
165     pStore = Ivy_CutComputeForNode( pMan, pNode, 5 );
166 p->timeCut += Abc_Clock() - clk;
167 
168     // go through the cuts
169 clk = Abc_Clock();
170     vFanout = Vec_PtrAlloc( 100 );
171     for ( c = 1; c < pStore->nCuts; c++ )
172     {
173         pCut = pStore->pCuts + c;
174         // consider only 4-input cuts
175         if ( pCut->nSize != 4 )
176             continue;
177         // skip the cuts with buffers
178         for ( i = 0; i < (int)pCut->nSize; i++ )
179             if ( Ivy_ObjIsBuf( Ivy_ManObj(pMan, Ivy_LeafId(pCut->pArray[i])) ) )
180                 break;
181         if ( i != pCut->nSize )
182         {
183             p->nCutsBad++;
184             continue;
185         }
186         p->nCutsGood++;
187         // get the fanin permutation
188 clk2 = Abc_Clock();
189         uTruth = 0xFFFF & Ivy_CutGetTruth( pMan, pNode, pCut->pArray, pCut->nSize );  // truth table
190 p->timeTruth += Abc_Clock() - clk2;
191         pPerm = p->pPerms4[ (int)p->pPerms[uTruth] ];
192         uPhase = p->pPhases[uTruth];
193         // collect fanins with the corresponding permutation/phase
194         Vec_PtrClear( p->vFaninsCur );
195         Vec_PtrFill( p->vFaninsCur, (int)pCut->nSize, 0 );
196         for ( i = 0; i < (int)pCut->nSize; i++ )
197         {
198             pFanin = Ivy_ManObj( pMan, Ivy_LeafId( pCut->pArray[(int)pPerm[i]] ) );
199             assert( Ivy_ObjIsNode(pFanin) || Ivy_ObjIsCi(pFanin) || Ivy_ObjIsConst1(pFanin) );
200             pFanin = Ivy_NotCond(pFanin, ((uPhase & (1<<i)) > 0) );
201             Vec_PtrWriteEntry( p->vFaninsCur, i, pFanin );
202         }
203 clk2 = Abc_Clock();
204         // mark the fanin boundary
205         Vec_PtrForEachEntry( Ivy_Obj_t *, p->vFaninsCur, pFanin, i )
206             Ivy_ObjRefsInc( Ivy_Regular(pFanin) );
207         // label MFFC with current ID
208         Ivy_ManIncrementTravId( pMan );
209         nNodesSaved = Ivy_ObjMffcLabel( pMan, pNode );
210         // label fanouts with the current ID
211 //        Ivy_ObjForEachFanout( pMan, pNode, vFanout, pFanout, i )
212 //            Ivy_ObjSetTravIdCurrent( pMan, pFanout );
213         // unmark the fanin boundary
214         Vec_PtrForEachEntry( Ivy_Obj_t *, p->vFaninsCur, pFanin, i )
215             Ivy_ObjRefsDec( Ivy_Regular(pFanin) );
216 p->timeMffc += Abc_Clock() - clk2;
217 
218         // evaluate the cut
219 clk2 = Abc_Clock();
220         pGraph = Rwt_CutEvaluateSeq( pMan, p, pNode, pCut, pPerm, p->vFaninsCur, nNodesSaved, &GainCur, uTruth );
221 p->timeEval += Abc_Clock() - clk2;
222 
223 
224         // check if the cut is better than the current best one
225         if ( pGraph != NULL && GainBest < GainCur )
226         {
227             // save this form
228             nNodesSaveCur = nNodesSaved;
229             GainBest   = GainCur;
230             p->pGraph  = pGraph;
231             p->pCut    = pCut;
232             p->pPerm   = pPerm;
233             p->fCompl  = ((uPhase & (1<<4)) > 0);
234             uTruthBest = uTruth;
235             // collect fanins in the
236             Vec_PtrClear( p->vFanins );
237             Vec_PtrForEachEntry( Ivy_Obj_t *, p->vFaninsCur, pFanin, i )
238                 Vec_PtrPush( p->vFanins, pFanin );
239         }
240     }
241     Vec_PtrFree( vFanout );
242 p->timeRes += Abc_Clock() - clk;
243 
244     if ( GainBest == -1 )
245         return -1;
246 /*
247     {
248     Ivy_Cut_t * pCut = p->pCut;
249     printf( "Node %5d. Using cut : {", Ivy_ObjId(pNode) );
250     for ( i = 0; i < pCut->nSize; i++ )
251         printf( " %d(%d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
252     printf( " }\n" );
253     }
254 */
255 
256 //clk3 = Abc_Clock();
257 //nNewClauses = Ivy_CutTruthPrint( pMan, p->pCut, uTruth );
258 //timeInv += Abc_Clock() - clk;
259 
260 //    nClauses += nNewClauses;
261 //    nMoves++;
262 //    if ( nNewClauses > 0 )
263 //        nMovesS++;
264 
265     // copy the leaves
266     Ivy_GraphPrepare( (Dec_Graph_t *)p->pGraph, (Ivy_Cut_t *)p->pCut, p->vFanins, p->pPerm );
267 
268     p->nScores[p->pMap[uTruthBest]]++;
269     p->nNodesGained += GainBest;
270     if ( fUseZeroCost || GainBest > 0 )
271         p->nNodesRewritten++;
272 
273 /*
274     if ( GainBest > 0 )
275     {
276         Ivy_Cut_t * pCut = p->pCut;
277         printf( "Node %5d. Using cut : {", Ivy_ObjId(pNode) );
278         for ( i = 0; i < pCut->nSize; i++ )
279             printf( " %5d(%2d)", Ivy_LeafId(pCut->pArray[i]), Ivy_LeafLat(pCut->pArray[i]) );
280         printf( " }\n" );
281     }
282 */
283 
284     // report the progress
285     if ( fVeryVerbose && GainBest > 0 )
286     {
287         printf( "Node %6d :   ", Ivy_ObjId(pNode) );
288         printf( "Fanins = %d. ", p->vFanins->nSize );
289         printf( "Save = %d.  ", nNodesSaveCur );
290         printf( "Add = %d.  ",  nNodesSaveCur-GainBest );
291         printf( "GAIN = %d.  ", GainBest );
292         printf( "Cone = %d.  ", p->pGraph? Dec_GraphNodeNum((Dec_Graph_t *)p->pGraph) : 0 );
293         printf( "Class = %d.  ", p->pMap[uTruthBest] );
294         printf( "\n" );
295     }
296     return GainBest;
297 }
298 
299 
300 /**Function*************************************************************
301 
302   Synopsis    [Evaluates the cut.]
303 
304   Description []
305 
306   SideEffects []
307 
308   SeeAlso     []
309 
310 ***********************************************************************/
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)311 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 )
312 {
313     Vec_Ptr_t * vSubgraphs;
314     Dec_Graph_t * pGraphBest = NULL; // Suppress "might be used uninitialized"
315     Dec_Graph_t * pGraphCur;
316     Rwt_Node_t * pNode;
317     int nNodesAdded, GainBest, i;
318     // find the matching class of subgraphs
319     vSubgraphs = Vec_VecEntry( p->vClasses, p->pMap[uTruth] );
320     p->nSubgraphs += vSubgraphs->nSize;
321     // determine the best subgraph
322     GainBest = -1;
323     Vec_PtrForEachEntry( Rwt_Node_t *, vSubgraphs, pNode, i )
324     {
325         // get the current graph
326         pGraphCur = (Dec_Graph_t *)pNode->pNext;
327 
328 //        if ( pRoot->Id == 8648 )
329 //        Dec_GraphPrint( stdout, pGraphCur, NULL, NULL );
330         // copy the leaves
331 //        Vec_PtrForEachEntry( Ivy_Obj_t *, vFaninsCur, pFanin, k )
332 //            Dec_GraphNode(pGraphCur, k)->pFunc = pFanin;
333         Ivy_GraphPrepare( pGraphCur, pCut, vFaninsCur, pPerm );
334 
335         // detect how many unlabeled nodes will be reused
336         nNodesAdded = Ivy_GraphToNetworkSeqCountSeq( pMan, pRoot, pGraphCur, nNodesSaved );
337         if ( nNodesAdded == -1 )
338             continue;
339         assert( nNodesSaved >= nNodesAdded );
340         // count the gain at this node
341         if ( GainBest < nNodesSaved - nNodesAdded )
342         {
343             GainBest   = nNodesSaved - nNodesAdded;
344             pGraphBest = pGraphCur;
345         }
346     }
347     if ( GainBest == -1 )
348         return NULL;
349     *pGainBest = GainBest;
350     return pGraphBest;
351 }
352 
353 /**Function*************************************************************
354 
355   Synopsis    []
356 
357   Description []
358 
359   SideEffects []
360 
361   SeeAlso     []
362 
363 ***********************************************************************/
Ivy_GraphPrepare(Dec_Graph_t * pGraph,Ivy_Cut_t * pCut,Vec_Ptr_t * vFanins,char * pPerm)364 void Ivy_GraphPrepare( Dec_Graph_t * pGraph, Ivy_Cut_t * pCut, Vec_Ptr_t * vFanins, char * pPerm )
365 {
366     Dec_Node_t * pNode, * pNode0, * pNode1;
367     int i;
368     assert( Dec_GraphLeaveNum(pGraph) == pCut->nSize );
369     assert( Vec_PtrSize(vFanins) == pCut->nSize );
370     // label the leaves with latch numbers
371     Dec_GraphForEachLeaf( pGraph, pNode, i )
372     {
373         pNode->pFunc = Vec_PtrEntry( vFanins, i );
374         pNode->nLat2 = Ivy_LeafLat( pCut->pArray[(int)pPerm[i]] );
375     }
376     // propagate latches through the nodes
377     Dec_GraphForEachNode( pGraph, pNode, i )
378     {
379         // get the children of this node
380         pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
381         pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
382         // distribute the latches
383         pNode->nLat2 = IVY_MIN( pNode0->nLat2, pNode1->nLat2 );
384         pNode->nLat0 = pNode0->nLat2 - pNode->nLat2;
385         pNode->nLat1 = pNode1->nLat2 - pNode->nLat2;
386     }
387 }
388 
389 /**Function*************************************************************
390 
391   Synopsis    [Counts the number of new nodes added when using this graph.]
392 
393   Description [AIG nodes for the fanins should be assigned to pNode->pFunc
394   of the leaves of the graph before calling this procedure.
395   Returns -1 if the number of nodes and levels exceeded the given limit or
396   the number of levels exceeded the maximum allowed level.]
397 
398   SideEffects []
399 
400   SeeAlso     []
401 
402 ***********************************************************************/
Ivy_GraphToNetworkSeqCountSeq(Ivy_Man_t * p,Ivy_Obj_t * pRoot,Dec_Graph_t * pGraph,int NodeMax)403 int Ivy_GraphToNetworkSeqCountSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int NodeMax )
404 {
405     Dec_Node_t * pNode, * pNode0, * pNode1;
406     Ivy_Obj_t * pAnd, * pAnd0, * pAnd1;
407     int i, k, Counter, fCompl;
408     // check for constant function or a literal
409     if ( Dec_GraphIsConst(pGraph) || Dec_GraphIsVar(pGraph) )
410         return 0;
411     // compute the AIG size after adding the internal nodes
412     Counter = 0;
413     Dec_GraphForEachNode( pGraph, pNode, i )
414     {
415         // get the children of this node
416         pNode0 = Dec_GraphNode( pGraph, pNode->eEdge0.Node );
417         pNode1 = Dec_GraphNode( pGraph, pNode->eEdge1.Node );
418         // get the AIG nodes corresponding to the children
419         pAnd0 = (Ivy_Obj_t *)pNode0->pFunc;
420         pAnd1 = (Ivy_Obj_t *)pNode1->pFunc;
421         // skip the latches
422         for ( k = 0; pAnd0 && k < (int)pNode->nLat0; k++ )
423         {
424             fCompl = Ivy_IsComplement(pAnd0);
425             pAnd0 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Regular(pAnd0), NULL, IVY_LATCH, IVY_INIT_DC) );
426             if ( pAnd0 )
427                 pAnd0 = Ivy_NotCond( pAnd0, fCompl );
428         }
429         for ( k = 0; pAnd1 && k < (int)pNode->nLat1; k++ )
430         {
431             fCompl = Ivy_IsComplement(pAnd1);
432             pAnd1 = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, Ivy_Regular(pAnd1), NULL, IVY_LATCH, IVY_INIT_DC) );
433             if ( pAnd1 )
434                 pAnd1 = Ivy_NotCond( pAnd1, fCompl );
435         }
436         // get the new node
437         if ( pAnd0 && pAnd1 )
438         {
439             // if they are both present, find the resulting node
440             pAnd0 = Ivy_NotCond( pAnd0, pNode->eEdge0.fCompl );
441             pAnd1 = Ivy_NotCond( pAnd1, pNode->eEdge1.fCompl );
442             assert( !Ivy_ObjIsLatch(Ivy_Regular(pAnd0)) || !Ivy_ObjIsLatch(Ivy_Regular(pAnd1)) );
443             if ( Ivy_Regular(pAnd0) == Ivy_Regular(pAnd1) || Ivy_ObjIsConst1(Ivy_Regular(pAnd0)) || Ivy_ObjIsConst1(Ivy_Regular(pAnd1)) )
444                 pAnd = Ivy_And( p, pAnd0, pAnd1 );
445             else
446                 pAnd = Ivy_TableLookup( p, Ivy_ObjCreateGhost(p, pAnd0, pAnd1, IVY_AND, IVY_INIT_NONE) );
447             // return -1 if the node is the same as the original root
448             if ( Ivy_Regular(pAnd) == pRoot )
449                 return -1;
450         }
451         else
452             pAnd = NULL;
453         // count the number of added nodes
454         if ( pAnd == NULL || Ivy_ObjIsTravIdCurrent(p, Ivy_Regular(pAnd)) )
455         {
456             if ( ++Counter > NodeMax )
457                 return -1;
458         }
459         pNode->pFunc = pAnd;
460     }
461     return Counter;
462 }
463 
464 
465 /**Function*************************************************************
466 
467   Synopsis    [Transforms the decomposition graph into the AIG.]
468 
469   Description [AIG nodes for the fanins should be assigned to pNode->pFunc
470   of the leaves of the graph before calling this procedure.]
471 
472   SideEffects []
473 
474   SeeAlso     []
475 
476 ***********************************************************************/
Ivy_GraphToNetworkSeq(Ivy_Man_t * p,Dec_Graph_t * pGraph)477 Ivy_Obj_t * Ivy_GraphToNetworkSeq( Ivy_Man_t * p, Dec_Graph_t * pGraph )
478 {
479     Ivy_Obj_t * pAnd0, * pAnd1;
480     Dec_Node_t * pNode = NULL; // Suppress "might be used uninitialized"
481     int i, k;
482     // check for constant function
483     if ( Dec_GraphIsConst(pGraph) )
484         return Ivy_NotCond( Ivy_ManConst1(p), Dec_GraphIsComplement(pGraph) );
485     // check for a literal
486     if ( Dec_GraphIsVar(pGraph) )
487     {
488         // get the variable node
489         pNode = Dec_GraphVar(pGraph);
490         // add the remaining latches
491         for ( k = 0; k < (int)pNode->nLat2; k++ )
492             pNode->pFunc = Ivy_Latch( p, (Ivy_Obj_t *)pNode->pFunc, IVY_INIT_DC );
493         return Ivy_NotCond( (Ivy_Obj_t *)pNode->pFunc, Dec_GraphIsComplement(pGraph) );
494     }
495     // build the AIG nodes corresponding to the AND gates of the graph
496     Dec_GraphForEachNode( pGraph, pNode, i )
497     {
498         pAnd0 = Ivy_NotCond( (Ivy_Obj_t *)Dec_GraphNode(pGraph, pNode->eEdge0.Node)->pFunc, pNode->eEdge0.fCompl );
499         pAnd1 = Ivy_NotCond( (Ivy_Obj_t *)Dec_GraphNode(pGraph, pNode->eEdge1.Node)->pFunc, pNode->eEdge1.fCompl );
500         // add the latches
501         for ( k = 0; k < (int)pNode->nLat0; k++ )
502             pAnd0 = Ivy_Latch( p, pAnd0, IVY_INIT_DC );
503         for ( k = 0; k < (int)pNode->nLat1; k++ )
504             pAnd1 = Ivy_Latch( p, pAnd1, IVY_INIT_DC );
505         // create the node
506         pNode->pFunc = Ivy_And( p, pAnd0, pAnd1 );
507     }
508     // add the remaining latches
509     for ( k = 0; k < (int)pNode->nLat2; k++ )
510         pNode->pFunc = Ivy_Latch( p, (Ivy_Obj_t *)pNode->pFunc, IVY_INIT_DC );
511     // complement the result if necessary
512     return Ivy_NotCond( (Ivy_Obj_t *)pNode->pFunc, Dec_GraphIsComplement(pGraph) );
513 }
514 
515 /**Function*************************************************************
516 
517   Synopsis    [Replaces MFFC of the node by the new factored form.]
518 
519   Description []
520 
521   SideEffects []
522 
523   SeeAlso     []
524 
525 ***********************************************************************/
Ivy_GraphUpdateNetworkSeq(Ivy_Man_t * p,Ivy_Obj_t * pRoot,Dec_Graph_t * pGraph,int nGain)526 void Ivy_GraphUpdateNetworkSeq( Ivy_Man_t * p, Ivy_Obj_t * pRoot, Dec_Graph_t * pGraph, int nGain )
527 {
528     Ivy_Obj_t * pRootNew;
529     int nNodesNew, nNodesOld;
530     nNodesOld = Ivy_ManNodeNum(p);
531     // create the new structure of nodes
532     pRootNew = Ivy_GraphToNetworkSeq( p, pGraph );
533     Ivy_ObjReplace( p, pRoot, pRootNew, 1, 0, 0 );
534     // compare the gains
535     nNodesNew = Ivy_ManNodeNum(p);
536     assert( nGain <= nNodesOld - nNodesNew );
537     // propagate the buffer
538     Ivy_ManPropagateBuffers( p, 0 );
539 }
540 
541 
542 
543 
544 
545 
546 
547 
548 
549 /**Function*************************************************************
550 
551   Synopsis    [Computes the truth table.]
552 
553   Description []
554 
555   SideEffects []
556 
557   SeeAlso     []
558 
559 ***********************************************************************/
Ivy_CutGetTruth_rec(Ivy_Man_t * p,int Leaf,int * pNums,int nNums)560 unsigned Ivy_CutGetTruth_rec( Ivy_Man_t * p, int Leaf, int * pNums, int nNums )
561 {
562     static unsigned uMasks[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
563     unsigned uTruth0, uTruth1;
564     Ivy_Obj_t * pObj;
565     int i;
566     for ( i = 0; i < nNums; i++ )
567         if ( Leaf == pNums[i] )
568             return uMasks[i];
569     pObj = Ivy_ManObj( p, Ivy_LeafId(Leaf) );
570     if ( Ivy_ObjIsLatch(pObj) )
571     {
572         assert( !Ivy_ObjFaninC0(pObj) );
573         Leaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pObj), Ivy_LeafLat(Leaf) + 1 );
574         return Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
575     }
576     assert( Ivy_ObjIsNode(pObj) || Ivy_ObjIsBuf(pObj) );
577     Leaf = Ivy_LeafCreate( Ivy_ObjFaninId0(pObj), Ivy_LeafLat(Leaf) );
578     uTruth0 = Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
579     if ( Ivy_ObjFaninC0(pObj) )
580         uTruth0 = ~uTruth0;
581     if ( Ivy_ObjIsBuf(pObj) )
582         return uTruth0;
583     Leaf = Ivy_LeafCreate( Ivy_ObjFaninId1(pObj), Ivy_LeafLat(Leaf) );
584     uTruth1 = Ivy_CutGetTruth_rec( p, Leaf, pNums, nNums );
585     if ( Ivy_ObjFaninC1(pObj) )
586         uTruth1 = ~uTruth1;
587     return uTruth0 & uTruth1;
588 }
589 
590 
591 /**Function*************************************************************
592 
593   Synopsis    [Computes the truth table.]
594 
595   Description []
596 
597   SideEffects []
598 
599   SeeAlso     []
600 
601 ***********************************************************************/
Ivy_CutGetTruth(Ivy_Man_t * p,Ivy_Obj_t * pObj,int * pNums,int nNums)602 unsigned Ivy_CutGetTruth( Ivy_Man_t * p, Ivy_Obj_t * pObj, int * pNums, int nNums )
603 {
604     assert( Ivy_ObjIsNode(pObj) );
605     assert( nNums < 6 );
606     return Ivy_CutGetTruth_rec( p, Ivy_LeafCreate(pObj->Id, 0), pNums, nNums );
607 }
608 
609 
610 
611 
612 
613 /**Function*************************************************************
614 
615   Synopsis    [Returns 1 if the cut can be constructed; 0 otherwise.]
616 
617   Description []
618 
619   SideEffects []
620 
621   SeeAlso     []
622 
623 ***********************************************************************/
Ivy_CutPrescreen(Ivy_Cut_t * pCut,int Id0,int Id1)624 static inline int Ivy_CutPrescreen( Ivy_Cut_t * pCut, int Id0, int Id1 )
625 {
626     int i;
627     if ( pCut->nSize < pCut->nSizeMax )
628         return 1;
629     for ( i = 0; i < pCut->nSize; i++ )
630         if ( pCut->pArray[i] == Id0 || pCut->pArray[i] == Id1 )
631             return 1;
632     return 0;
633 }
634 
635 /**Function*************************************************************
636 
637   Synopsis    [Derives new cut.]
638 
639   Description []
640 
641   SideEffects []
642 
643   SeeAlso     []
644 
645 ***********************************************************************/
Ivy_CutDeriveNew2(Ivy_Cut_t * pCut,Ivy_Cut_t * pCutNew,int IdOld,int IdNew0,int IdNew1)646 static inline int Ivy_CutDeriveNew2( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
647 {
648     unsigned uHash = 0;
649     int i, k;
650     assert( pCut->nSize > 0 );
651     assert( IdNew0 < IdNew1 );
652     for ( i = k = 0; i < pCut->nSize; i++ )
653     {
654         if ( pCut->pArray[i] == IdOld )
655             continue;
656         if ( IdNew0 >= 0 )
657         {
658             if ( IdNew0 <= pCut->pArray[i] )
659             {
660                 if ( IdNew0 < pCut->pArray[i] )
661                 {
662                     if ( k == pCut->nSizeMax )
663                         return 0;
664                     pCutNew->pArray[ k++ ] = IdNew0;
665                     uHash |= Ivy_CutHashValue( IdNew0 );
666                 }
667                 IdNew0 = -1;
668             }
669         }
670         if ( IdNew1 >= 0 )
671         {
672             if ( IdNew1 <= pCut->pArray[i] )
673             {
674                 if ( IdNew1 < pCut->pArray[i] )
675                 {
676                     if ( k == pCut->nSizeMax )
677                         return 0;
678                     pCutNew->pArray[ k++ ] = IdNew1;
679                     uHash |= Ivy_CutHashValue( IdNew1 );
680                 }
681                 IdNew1 = -1;
682             }
683         }
684         if ( k == pCut->nSizeMax )
685             return 0;
686         pCutNew->pArray[ k++ ] = pCut->pArray[i];
687         uHash |= Ivy_CutHashValue( pCut->pArray[i] );
688     }
689     if ( IdNew0 >= 0 )
690     {
691         if ( k == pCut->nSizeMax )
692             return 0;
693         pCutNew->pArray[ k++ ] = IdNew0;
694         uHash |= Ivy_CutHashValue( IdNew0 );
695     }
696     if ( IdNew1 >= 0 )
697     {
698         if ( k == pCut->nSizeMax )
699             return 0;
700         pCutNew->pArray[ k++ ] = IdNew1;
701         uHash |= Ivy_CutHashValue( IdNew1 );
702     }
703     pCutNew->nSize = k;
704     pCutNew->uHash = uHash;
705     assert( pCutNew->nSize <= pCut->nSizeMax );
706     for ( i = 1; i < pCutNew->nSize; i++ )
707         assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
708     return 1;
709 }
710 
711 /**Function*************************************************************
712 
713   Synopsis    [Derives new cut.]
714 
715   Description []
716 
717   SideEffects []
718 
719   SeeAlso     []
720 
721 ***********************************************************************/
Ivy_CutDeriveNew(Ivy_Cut_t * pCut,Ivy_Cut_t * pCutNew,int IdOld,int IdNew0,int IdNew1)722 static inline int Ivy_CutDeriveNew( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
723 {
724     unsigned uHash = 0;
725     int i, k;
726     assert( pCut->nSize > 0 );
727     assert( IdNew0 < IdNew1 );
728     for ( i = k = 0; i < pCut->nSize; i++ )
729     {
730         if ( pCut->pArray[i] == IdOld )
731             continue;
732         if ( IdNew0 <= pCut->pArray[i] )
733         {
734             if ( IdNew0 < pCut->pArray[i] )
735             {
736                 pCutNew->pArray[ k++ ] = IdNew0;
737                 uHash |= Ivy_CutHashValue( IdNew0 );
738             }
739             IdNew0 = 0x7FFFFFFF;
740         }
741         if ( IdNew1 <= pCut->pArray[i] )
742         {
743             if ( IdNew1 < pCut->pArray[i] )
744             {
745                 pCutNew->pArray[ k++ ] = IdNew1;
746                 uHash |= Ivy_CutHashValue( IdNew1 );
747             }
748             IdNew1 = 0x7FFFFFFF;
749         }
750         pCutNew->pArray[ k++ ] = pCut->pArray[i];
751         uHash |= Ivy_CutHashValue( pCut->pArray[i] );
752     }
753     if ( IdNew0 < 0x7FFFFFFF )
754     {
755         pCutNew->pArray[ k++ ] = IdNew0;
756         uHash |= Ivy_CutHashValue( IdNew0 );
757     }
758     if ( IdNew1 < 0x7FFFFFFF )
759     {
760         pCutNew->pArray[ k++ ] = IdNew1;
761         uHash |= Ivy_CutHashValue( IdNew1 );
762     }
763     pCutNew->nSize = k;
764     pCutNew->uHash = uHash;
765     assert( pCutNew->nSize <= pCut->nSizeMax );
766 //    for ( i = 1; i < pCutNew->nSize; i++ )
767 //        assert( pCutNew->pArray[i-1] < pCutNew->pArray[i] );
768     return 1;
769 }
770 
771 /**Function*************************************************************
772 
773   Synopsis    [Find the hash value of the cut.]
774 
775   Description []
776 
777   SideEffects []
778 
779   SeeAlso     []
780 
781 ***********************************************************************/
Ivy_NodeCutHash(Ivy_Cut_t * pCut)782 static inline unsigned Ivy_NodeCutHash( Ivy_Cut_t * pCut )
783 {
784     int i;
785     pCut->uHash = 0;
786     for ( i = 0; i < pCut->nSize; i++ )
787         pCut->uHash |= (1 << (pCut->pArray[i] % 31));
788     return pCut->uHash;
789 }
790 
791 /**Function*************************************************************
792 
793   Synopsis    [Derives new cut.]
794 
795   Description []
796 
797   SideEffects []
798 
799   SeeAlso     []
800 
801 ***********************************************************************/
Ivy_CutDeriveNew3(Ivy_Cut_t * pCut,Ivy_Cut_t * pCutNew,int IdOld,int IdNew0,int IdNew1)802 static inline int Ivy_CutDeriveNew3( Ivy_Cut_t * pCut, Ivy_Cut_t * pCutNew, int IdOld, int IdNew0, int IdNew1 )
803 {
804     int i, k;
805     assert( pCut->nSize > 0 );
806     assert( IdNew0 < IdNew1 );
807     for ( i = k = 0; i < pCut->nSize; i++ )
808     {
809         if ( pCut->pArray[i] == IdOld )
810             continue;
811         if ( IdNew0 <= pCut->pArray[i] )
812         {
813             if ( IdNew0 < pCut->pArray[i] )
814                 pCutNew->pArray[ k++ ] = IdNew0;
815             IdNew0 = 0x7FFFFFFF;
816         }
817         if ( IdNew1 <= pCut->pArray[i] )
818         {
819             if ( IdNew1 < pCut->pArray[i] )
820                 pCutNew->pArray[ k++ ] = IdNew1;
821             IdNew1 = 0x7FFFFFFF;
822         }
823         pCutNew->pArray[ k++ ] = pCut->pArray[i];
824     }
825     if ( IdNew0 < 0x7FFFFFFF )
826         pCutNew->pArray[ k++ ] = IdNew0;
827     if ( IdNew1 < 0x7FFFFFFF )
828         pCutNew->pArray[ k++ ] = IdNew1;
829     pCutNew->nSize = k;
830     assert( pCutNew->nSize <= pCut->nSizeMax );
831     Ivy_NodeCutHash( pCutNew );
832     return 1;
833 }
834 
835 /**Function*************************************************************
836 
837   Synopsis    [Returns 1 if pDom is contained in pCut.]
838 
839   Description []
840 
841   SideEffects []
842 
843   SeeAlso     []
844 
845 ***********************************************************************/
Ivy_CutCheckDominance(Ivy_Cut_t * pDom,Ivy_Cut_t * pCut)846 static inline int Ivy_CutCheckDominance( Ivy_Cut_t * pDom, Ivy_Cut_t * pCut )
847 {
848     int i, k;
849     for ( i = 0; i < pDom->nSize; i++ )
850     {
851         assert( i==0 || pDom->pArray[i-1] < pDom->pArray[i] );
852         for ( k = 0; k < pCut->nSize; k++ )
853             if ( pDom->pArray[i] == pCut->pArray[k] )
854                 break;
855         if ( k == pCut->nSize ) // node i in pDom is not contained in pCut
856             return 0;
857     }
858     // every node in pDom is contained in pCut
859     return 1;
860 }
861 
862 /**Function*************************************************************
863 
864   Synopsis    [Check if the cut exists.]
865 
866   Description [Returns 1 if the cut exists.]
867 
868   SideEffects []
869 
870   SeeAlso     []
871 
872 ***********************************************************************/
Ivy_CutFindOrAddFilter(Ivy_Store_t * pCutStore,Ivy_Cut_t * pCutNew)873 int Ivy_CutFindOrAddFilter( Ivy_Store_t * pCutStore, Ivy_Cut_t * pCutNew )
874 {
875     Ivy_Cut_t * pCut;
876     int i, k;
877     assert( pCutNew->uHash );
878     // try to find the cut
879     for ( i = 0; i < pCutStore->nCuts; i++ )
880     {
881         pCut = pCutStore->pCuts + i;
882         if ( pCut->nSize == 0 )
883             continue;
884         if ( pCut->nSize == pCutNew->nSize )
885         {
886             if ( pCut->uHash == pCutNew->uHash )
887             {
888                 for ( k = 0; k < pCutNew->nSize; k++ )
889                     if ( pCut->pArray[k] != pCutNew->pArray[k] )
890                         break;
891                 if ( k == pCutNew->nSize )
892                     return 1;
893             }
894             continue;
895         }
896         if ( pCut->nSize < pCutNew->nSize )
897         {
898             // skip the non-contained cuts
899             if ( (pCut->uHash & pCutNew->uHash) != pCut->uHash )
900                 continue;
901             // check containment seriously
902             if ( Ivy_CutCheckDominance( pCut, pCutNew ) )
903                 return 1;
904             continue;
905         }
906         // check potential containment of other cut
907 
908         // skip the non-contained cuts
909         if ( (pCut->uHash & pCutNew->uHash) != pCutNew->uHash )
910             continue;
911         // check containment seriously
912         if ( Ivy_CutCheckDominance( pCutNew, pCut ) )
913         {
914             // remove the current cut
915             pCut->nSize = 0;
916         }
917     }
918     assert( pCutStore->nCuts < pCutStore->nCutsMax );
919     // add the cut
920     pCut = pCutStore->pCuts + pCutStore->nCuts++;
921     *pCut = *pCutNew;
922     return 0;
923 }
924 
925 /**Function*************************************************************
926 
927   Synopsis    [Compresses the cut representation.]
928 
929   Description []
930 
931   SideEffects []
932 
933   SeeAlso     []
934 
935 ***********************************************************************/
Ivy_CutCompactAll(Ivy_Store_t * pCutStore)936 void Ivy_CutCompactAll( Ivy_Store_t * pCutStore )
937 {
938     Ivy_Cut_t * pCut;
939     int i, k;
940     pCutStore->nCutsM = 0;
941     for ( i = k = 0; i < pCutStore->nCuts; i++ )
942     {
943         pCut = pCutStore->pCuts + i;
944         if ( pCut->nSize == 0 )
945             continue;
946         if ( pCut->nSize < pCut->nSizeMax )
947             pCutStore->nCutsM++;
948         pCutStore->pCuts[k++] = *pCut;
949     }
950     pCutStore->nCuts = k;
951 }
952 
953 /**Function*************************************************************
954 
955   Synopsis    [Print the cut.]
956 
957   Description []
958 
959   SideEffects []
960 
961   SeeAlso     []
962 
963 ***********************************************************************/
Ivy_CutPrintForNode(Ivy_Cut_t * pCut)964 void Ivy_CutPrintForNode( Ivy_Cut_t * pCut )
965 {
966     int i;
967     assert( pCut->nSize > 0 );
968     printf( "%d : {", pCut->nSize );
969     for ( i = 0; i < pCut->nSize; i++ )
970         printf( " %d", pCut->pArray[i] );
971     printf( " }\n" );
972 }
973 
974 /**Function*************************************************************
975 
976   Synopsis    []
977 
978   Description []
979 
980   SideEffects []
981 
982   SeeAlso     []
983 
984 ***********************************************************************/
Ivy_CutPrintForNodes(Ivy_Store_t * pCutStore)985 void Ivy_CutPrintForNodes( Ivy_Store_t * pCutStore )
986 {
987     int i;
988     printf( "Node %d\n", pCutStore->pCuts[0].pArray[0] );
989     for ( i = 0; i < pCutStore->nCuts; i++ )
990         Ivy_CutPrintForNode( pCutStore->pCuts + i );
991 }
992 
993 /**Function*************************************************************
994 
995   Synopsis    []
996 
997   Description []
998 
999   SideEffects []
1000 
1001   SeeAlso     []
1002 
1003 ***********************************************************************/
Ivy_CutReadLeaf(Ivy_Obj_t * pFanin)1004 static inline int Ivy_CutReadLeaf( Ivy_Obj_t * pFanin )
1005 {
1006     int nLats, iLeaf;
1007     assert( !Ivy_IsComplement(pFanin) );
1008     if ( !Ivy_ObjIsLatch(pFanin) )
1009         return Ivy_LeafCreate( pFanin->Id, 0 );
1010     iLeaf = Ivy_CutReadLeaf(Ivy_ObjFanin0(pFanin));
1011     nLats = Ivy_LeafLat(iLeaf);
1012     assert( nLats < IVY_LEAF_MASK );
1013     return 1 + iLeaf;
1014 }
1015 
1016 /**Function*************************************************************
1017 
1018   Synopsis    []
1019 
1020   Description []
1021 
1022   SideEffects []
1023 
1024   SeeAlso     []
1025 
1026 ***********************************************************************/
Ivy_CutComputeForNode(Ivy_Man_t * p,Ivy_Obj_t * pObj,int nLeaves)1027 Ivy_Store_t * Ivy_CutComputeForNode( Ivy_Man_t * p, Ivy_Obj_t * pObj, int nLeaves )
1028 {
1029     static Ivy_Store_t CutStore, * pCutStore = &CutStore;
1030     Ivy_Cut_t CutNew, * pCutNew = &CutNew, * pCut;
1031     Ivy_Obj_t * pLeaf;
1032     int i, k, Temp, nLats, iLeaf0, iLeaf1;
1033 
1034     assert( nLeaves <= IVY_CUT_INPUT );
1035 
1036     // start the structure
1037     pCutStore->nCuts = 0;
1038     pCutStore->nCutsMax = IVY_CUT_LIMIT;
1039     // start the trivial cut
1040     pCutNew->uHash = 0;
1041     pCutNew->nSize = 1;
1042     pCutNew->nSizeMax = nLeaves;
1043     pCutNew->pArray[0] = Ivy_LeafCreate( pObj->Id, 0 );
1044     pCutNew->uHash = Ivy_CutHashValue( pCutNew->pArray[0] );
1045     // add the trivial cut
1046     pCutStore->pCuts[pCutStore->nCuts++] = *pCutNew;
1047     assert( pCutStore->nCuts == 1 );
1048 
1049     // explore the cuts
1050     for ( i = 0; i < pCutStore->nCuts; i++ )
1051     {
1052         // expand this cut
1053         pCut = pCutStore->pCuts + i;
1054         if ( pCut->nSize == 0 )
1055             continue;
1056         for ( k = 0; k < pCut->nSize; k++ )
1057         {
1058             pLeaf = Ivy_ManObj( p, Ivy_LeafId(pCut->pArray[k]) );
1059             if ( Ivy_ObjIsCi(pLeaf) || Ivy_ObjIsConst1(pLeaf) )
1060                 continue;
1061             assert( Ivy_ObjIsNode(pLeaf) );
1062             nLats = Ivy_LeafLat(pCut->pArray[k]);
1063 
1064             // get the fanins fanins
1065             iLeaf0 = Ivy_CutReadLeaf( Ivy_ObjFanin0(pLeaf) );
1066             iLeaf1 = Ivy_CutReadLeaf( Ivy_ObjFanin1(pLeaf) );
1067             assert( nLats + Ivy_LeafLat(iLeaf0) < IVY_LEAF_MASK && nLats + Ivy_LeafLat(iLeaf1) < IVY_LEAF_MASK );
1068             iLeaf0 = nLats + iLeaf0;
1069             iLeaf1 = nLats + iLeaf1;
1070             if ( !Ivy_CutPrescreen( pCut, iLeaf0, iLeaf1 ) )
1071                 continue;
1072             // the given cut exist
1073             if ( iLeaf0 > iLeaf1 )
1074                 Temp = iLeaf0, iLeaf0 = iLeaf1, iLeaf1 = Temp;
1075             // create the new cut
1076             if ( !Ivy_CutDeriveNew( pCut, pCutNew, pCut->pArray[k], iLeaf0, iLeaf1 ) )
1077                 continue;
1078             // add the cut
1079             Ivy_CutFindOrAddFilter( pCutStore, pCutNew );
1080             if ( pCutStore->nCuts == IVY_CUT_LIMIT )
1081                 break;
1082         }
1083         if ( pCutStore->nCuts == IVY_CUT_LIMIT )
1084             break;
1085     }
1086     if ( pCutStore->nCuts == IVY_CUT_LIMIT )
1087         pCutStore->fSatur = 1;
1088     else
1089         pCutStore->fSatur = 0;
1090 //    printf( "%d ", pCutStore->nCuts );
1091     Ivy_CutCompactAll( pCutStore );
1092 //    printf( "%d \n", pCutStore->nCuts );
1093 //    Ivy_CutPrintForNodes( pCutStore );
1094     return pCutStore;
1095 }
1096 
1097 /**Function*************************************************************
1098 
1099   Synopsis    []
1100 
1101   Description []
1102 
1103   SideEffects []
1104 
1105   SeeAlso     []
1106 
1107 ***********************************************************************/
Ivy_CutComputeAll(Ivy_Man_t * p,int nInputs)1108 void Ivy_CutComputeAll( Ivy_Man_t * p, int nInputs )
1109 {
1110     Ivy_Store_t * pStore;
1111     Ivy_Obj_t * pObj;
1112     int i, nCutsTotal, nCutsTotalM, nNodeTotal, nNodeOver;
1113     abctime clk = Abc_Clock();
1114     if ( nInputs > IVY_CUT_INPUT )
1115     {
1116         printf( "Cannot compute cuts for more than %d inputs.\n", IVY_CUT_INPUT );
1117         return;
1118     }
1119     nNodeTotal = nNodeOver = 0;
1120     nCutsTotal = nCutsTotalM = -Ivy_ManNodeNum(p);
1121     Ivy_ManForEachObj( p, pObj, i )
1122     {
1123         if ( !Ivy_ObjIsNode(pObj) )
1124             continue;
1125         pStore = Ivy_CutComputeForNode( p, pObj, nInputs );
1126         nCutsTotal  += pStore->nCuts;
1127         nCutsTotalM += pStore->nCutsM;
1128         nNodeOver   += pStore->fSatur;
1129         nNodeTotal++;
1130     }
1131     printf( "All = %6d. Minus = %6d. Triv = %6d.   Node = %6d. Satur = %6d.  ",
1132         nCutsTotal, nCutsTotalM, Ivy_ManPiNum(p) + Ivy_ManNodeNum(p), nNodeTotal, nNodeOver );
1133     ABC_PRT( "Time", Abc_Clock() - clk );
1134 }
1135 
1136 ////////////////////////////////////////////////////////////////////////
1137 ///                       END OF FILE                                ///
1138 ////////////////////////////////////////////////////////////////////////
1139 
1140 
1141 ABC_NAMESPACE_IMPL_END
1142 
1143