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