| /**CFile**************************************************************** |
| |
| FileName [extraBddTime.c] |
| |
| PackageName [extra] |
| |
| Synopsis [Procedures to control runtime in BDD operators.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 2.0. Started - September 1, 2003.] |
| |
| Revision [$Id: extraBddTime.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "extraBdd.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Constant declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| #define CHECK_FACTOR 10 |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Stucture declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Type declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Variable declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Macro declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /**AutomaticStart*************************************************************/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Static function prototypes */ |
| /*---------------------------------------------------------------------------*/ |
| |
| static DdNode * cuddBddAndRecurTime( DdManager * manager, DdNode * f, DdNode * g, int * pRecCalls, int TimeOut ); |
| static DdNode * cuddBddAndAbstractRecurTime( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube, int * pRecCalls, int TimeOut ); |
| static DdNode * extraTransferPermuteTime( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute, int TimeOut ); |
| static DdNode * extraTransferPermuteRecurTime( DdManager * ddS, DdManager * ddD, DdNode * f, st__table * table, int * Permute, int TimeOut ); |
| |
| /**AutomaticEnd***************************************************************/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of exported functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Computes the conjunction of two BDDs f and g.] |
| |
| Description [Computes the conjunction of two BDDs f and g. Returns a |
| pointer to the resulting BDD if successful; NULL if the intermediate |
| result blows up.] |
| |
| SideEffects [None] |
| |
| SeeAlso [Cudd_bddIte Cudd_addApply Cudd_bddAndAbstract Cudd_bddIntersect |
| Cudd_bddOr Cudd_bddNand Cudd_bddNor Cudd_bddXor Cudd_bddXnor] |
| |
| ******************************************************************************/ |
| DdNode * |
| Extra_bddAndTime( |
| DdManager * dd, |
| DdNode * f, |
| DdNode * g, |
| int TimeOut) |
| { |
| DdNode *res; |
| int Counter = 0; |
| |
| do { |
| dd->reordered = 0; |
| res = cuddBddAndRecurTime(dd,f,g, &Counter, TimeOut); |
| } while (dd->reordered == 1); |
| return(res); |
| |
| } /* end of Extra_bddAndTime */ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Takes the AND of two BDDs and simultaneously abstracts the |
| variables in cube.] |
| |
| Description [Takes the AND of two BDDs and simultaneously abstracts |
| the variables in cube. The variables are existentially abstracted. |
| Returns a pointer to the result is successful; NULL otherwise. |
| Cudd_bddAndAbstract implements the semiring matrix multiplication |
| algorithm for the boolean semiring.] |
| |
| SideEffects [None] |
| |
| SeeAlso [Cudd_addMatrixMultiply Cudd_addTriangle Cudd_bddAnd] |
| |
| ******************************************************************************/ |
| DdNode * |
| Extra_bddAndAbstractTime( |
| DdManager * manager, |
| DdNode * f, |
| DdNode * g, |
| DdNode * cube, |
| int TimeOut) |
| { |
| DdNode *res; |
| int Counter = 0; |
| |
| do { |
| manager->reordered = 0; |
| res = cuddBddAndAbstractRecurTime(manager, f, g, cube, &Counter, TimeOut); |
| } while (manager->reordered == 1); |
| return(res); |
| |
| } /* end of Extra_bddAndAbstractTime */ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Convert a {A,B}DD from a manager to another with variable remapping.] |
| |
| Description [Convert a {A,B}DD from a manager to another one. The orders of the |
| variables in the two managers may be different. Returns a |
| pointer to the {A,B}DD in the destination manager if successful; NULL |
| otherwise. The i-th entry in the array Permute tells what is the index |
| of the i-th variable from the old manager in the new manager.] |
| |
| SideEffects [None] |
| |
| SeeAlso [] |
| |
| ******************************************************************************/ |
| DdNode * Extra_TransferPermuteTime( DdManager * ddSource, DdManager * ddDestination, DdNode * f, int * Permute, int TimeOut ) |
| { |
| DdNode * bRes; |
| do |
| { |
| ddDestination->reordered = 0; |
| bRes = extraTransferPermuteTime( ddSource, ddDestination, f, Permute, TimeOut ); |
| } |
| while ( ddDestination->reordered == 1 ); |
| return ( bRes ); |
| |
| } /* end of Extra_TransferPermuteTime */ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of internal functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Implements the recursive step of Cudd_bddAnd.] |
| |
| Description [Implements the recursive step of Cudd_bddAnd by taking |
| the conjunction of two BDDs. Returns a pointer to the result is |
| successful; NULL otherwise.] |
| |
| SideEffects [None] |
| |
| SeeAlso [Cudd_bddAnd] |
| |
| ******************************************************************************/ |
| DdNode * |
| cuddBddAndRecurTime( |
| DdManager * manager, |
| DdNode * f, |
| DdNode * g, |
| int * pRecCalls, |
| int TimeOut) |
| { |
| DdNode *F, *fv, *fnv, *G, *gv, *gnv; |
| DdNode *one, *r, *t, *e; |
| unsigned int topf, topg, index; |
| |
| statLine(manager); |
| one = DD_ONE(manager); |
| |
| /* Terminal cases. */ |
| F = Cudd_Regular(f); |
| G = Cudd_Regular(g); |
| if (F == G) { |
| if (f == g) return(f); |
| else return(Cudd_Not(one)); |
| } |
| if (F == one) { |
| if (f == one) return(g); |
| else return(f); |
| } |
| if (G == one) { |
| if (g == one) return(f); |
| else return(g); |
| } |
| |
| /* At this point f and g are not constant. */ |
| if (f > g) { /* Try to increase cache efficiency. */ |
| DdNode *tmp = f; |
| f = g; |
| g = tmp; |
| F = Cudd_Regular(f); |
| G = Cudd_Regular(g); |
| } |
| |
| /* Check cache. */ |
| if (F->ref != 1 || G->ref != 1) { |
| r = cuddCacheLookup2(manager, Cudd_bddAnd, f, g); |
| if (r != NULL) return(r); |
| } |
| |
| // if ( TimeOut && ((*pRecCalls)++ % CHECK_FACTOR) == 0 && TimeOut < Abc_Clock() ) |
| if ( TimeOut && Abc_Clock() > TimeOut ) |
| return NULL; |
| |
| /* Here we can skip the use of cuddI, because the operands are known |
| ** to be non-constant. |
| */ |
| topf = manager->perm[F->index]; |
| topg = manager->perm[G->index]; |
| |
| /* Compute cofactors. */ |
| if (topf <= topg) { |
| index = F->index; |
| fv = cuddT(F); |
| fnv = cuddE(F); |
| if (Cudd_IsComplement(f)) { |
| fv = Cudd_Not(fv); |
| fnv = Cudd_Not(fnv); |
| } |
| } else { |
| index = G->index; |
| fv = fnv = f; |
| } |
| |
| if (topg <= topf) { |
| gv = cuddT(G); |
| gnv = cuddE(G); |
| if (Cudd_IsComplement(g)) { |
| gv = Cudd_Not(gv); |
| gnv = Cudd_Not(gnv); |
| } |
| } else { |
| gv = gnv = g; |
| } |
| |
| t = cuddBddAndRecurTime(manager, fv, gv, pRecCalls, TimeOut); |
| if (t == NULL) return(NULL); |
| cuddRef(t); |
| |
| e = cuddBddAndRecurTime(manager, fnv, gnv, pRecCalls, TimeOut); |
| if (e == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| return(NULL); |
| } |
| cuddRef(e); |
| |
| if (t == e) { |
| r = t; |
| } else { |
| if (Cudd_IsComplement(t)) { |
| r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); |
| if (r == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| Cudd_IterDerefBdd(manager, e); |
| return(NULL); |
| } |
| r = Cudd_Not(r); |
| } else { |
| r = cuddUniqueInter(manager,(int)index,t,e); |
| if (r == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| Cudd_IterDerefBdd(manager, e); |
| return(NULL); |
| } |
| } |
| } |
| cuddDeref(e); |
| cuddDeref(t); |
| if (F->ref != 1 || G->ref != 1) |
| cuddCacheInsert2(manager, Cudd_bddAnd, f, g, r); |
| return(r); |
| |
| } /* end of cuddBddAndRecur */ |
| |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Takes the AND of two BDDs and simultaneously abstracts the |
| variables in cube.] |
| |
| Description [Takes the AND of two BDDs and simultaneously abstracts |
| the variables in cube. The variables are existentially abstracted. |
| Returns a pointer to the result is successful; NULL otherwise.] |
| |
| SideEffects [None] |
| |
| SeeAlso [Cudd_bddAndAbstract] |
| |
| ******************************************************************************/ |
| DdNode * |
| cuddBddAndAbstractRecurTime( |
| DdManager * manager, |
| DdNode * f, |
| DdNode * g, |
| DdNode * cube, |
| int * pRecCalls, |
| int TimeOut) |
| { |
| DdNode *F, *ft, *fe, *G, *gt, *ge; |
| DdNode *one, *zero, *r, *t, *e; |
| unsigned int topf, topg, topcube, top, index; |
| |
| statLine(manager); |
| one = DD_ONE(manager); |
| zero = Cudd_Not(one); |
| |
| /* Terminal cases. */ |
| if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); |
| if (f == one && g == one) return(one); |
| |
| if (cube == one) { |
| return(cuddBddAndRecurTime(manager, f, g, pRecCalls, TimeOut)); |
| } |
| if (f == one || f == g) { |
| return(cuddBddExistAbstractRecur(manager, g, cube)); |
| } |
| if (g == one) { |
| return(cuddBddExistAbstractRecur(manager, f, cube)); |
| } |
| /* At this point f, g, and cube are not constant. */ |
| |
| if (f > g) { /* Try to increase cache efficiency. */ |
| DdNode *tmp = f; |
| f = g; |
| g = tmp; |
| } |
| |
| /* Here we can skip the use of cuddI, because the operands are known |
| ** to be non-constant. |
| */ |
| F = Cudd_Regular(f); |
| G = Cudd_Regular(g); |
| topf = manager->perm[F->index]; |
| topg = manager->perm[G->index]; |
| top = ddMin(topf, topg); |
| topcube = manager->perm[cube->index]; |
| |
| while (topcube < top) { |
| cube = cuddT(cube); |
| if (cube == one) { |
| return(cuddBddAndRecurTime(manager, f, g, pRecCalls, TimeOut)); |
| } |
| topcube = manager->perm[cube->index]; |
| } |
| /* Now, topcube >= top. */ |
| |
| /* Check cache. */ |
| if (F->ref != 1 || G->ref != 1) { |
| r = cuddCacheLookup(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube); |
| if (r != NULL) { |
| return(r); |
| } |
| } |
| |
| // if ( TimeOut && ((*pRecCalls)++ % CHECK_FACTOR) == 0 && TimeOut < Abc_Clock() ) |
| if ( TimeOut && Abc_Clock() > TimeOut ) |
| return NULL; |
| |
| if (topf == top) { |
| index = F->index; |
| ft = cuddT(F); |
| fe = cuddE(F); |
| if (Cudd_IsComplement(f)) { |
| ft = Cudd_Not(ft); |
| fe = Cudd_Not(fe); |
| } |
| } else { |
| index = G->index; |
| ft = fe = f; |
| } |
| |
| if (topg == top) { |
| gt = cuddT(G); |
| ge = cuddE(G); |
| if (Cudd_IsComplement(g)) { |
| gt = Cudd_Not(gt); |
| ge = Cudd_Not(ge); |
| } |
| } else { |
| gt = ge = g; |
| } |
| |
| if (topcube == top) { /* quantify */ |
| DdNode *Cube = cuddT(cube); |
| t = cuddBddAndAbstractRecurTime(manager, ft, gt, Cube, pRecCalls, TimeOut); |
| if (t == NULL) return(NULL); |
| /* Special case: 1 OR anything = 1. Hence, no need to compute |
| ** the else branch if t is 1. Likewise t + t * anything == t. |
| ** Notice that t == fe implies that fe does not depend on the |
| ** variables in Cube. Likewise for t == ge. |
| */ |
| if (t == one || t == fe || t == ge) { |
| if (F->ref != 1 || G->ref != 1) |
| cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, |
| f, g, cube, t); |
| return(t); |
| } |
| cuddRef(t); |
| /* Special case: t + !t * anything == t + anything. */ |
| if (t == Cudd_Not(fe)) { |
| e = cuddBddExistAbstractRecur(manager, ge, Cube); |
| } else if (t == Cudd_Not(ge)) { |
| e = cuddBddExistAbstractRecur(manager, fe, Cube); |
| } else { |
| e = cuddBddAndAbstractRecurTime(manager, fe, ge, Cube, pRecCalls, TimeOut); |
| } |
| if (e == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| return(NULL); |
| } |
| if (t == e) { |
| r = t; |
| cuddDeref(t); |
| } else { |
| cuddRef(e); |
| r = cuddBddAndRecurTime(manager, Cudd_Not(t), Cudd_Not(e), pRecCalls, TimeOut); |
| if (r == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| Cudd_IterDerefBdd(manager, e); |
| return(NULL); |
| } |
| r = Cudd_Not(r); |
| cuddRef(r); |
| Cudd_DelayedDerefBdd(manager, t); |
| Cudd_DelayedDerefBdd(manager, e); |
| cuddDeref(r); |
| } |
| } else { |
| t = cuddBddAndAbstractRecurTime(manager, ft, gt, cube, pRecCalls, TimeOut); |
| if (t == NULL) return(NULL); |
| cuddRef(t); |
| e = cuddBddAndAbstractRecurTime(manager, fe, ge, cube, pRecCalls, TimeOut); |
| if (e == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| return(NULL); |
| } |
| if (t == e) { |
| r = t; |
| cuddDeref(t); |
| } else { |
| cuddRef(e); |
| if (Cudd_IsComplement(t)) { |
| r = cuddUniqueInter(manager, (int) index, |
| Cudd_Not(t), Cudd_Not(e)); |
| if (r == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| Cudd_IterDerefBdd(manager, e); |
| return(NULL); |
| } |
| r = Cudd_Not(r); |
| } else { |
| r = cuddUniqueInter(manager,(int)index,t,e); |
| if (r == NULL) { |
| Cudd_IterDerefBdd(manager, t); |
| Cudd_IterDerefBdd(manager, e); |
| return(NULL); |
| } |
| } |
| cuddDeref(e); |
| cuddDeref(t); |
| } |
| } |
| |
| if (F->ref != 1 || G->ref != 1) |
| cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube, r); |
| return (r); |
| |
| } /* end of cuddBddAndAbstractRecur */ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of static functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Convert a BDD from a manager to another one.] |
| |
| Description [Convert a BDD from a manager to another one. Returns a |
| pointer to the BDD in the destination manager if successful; NULL |
| otherwise.] |
| |
| SideEffects [None] |
| |
| SeeAlso [Extra_TransferPermute] |
| |
| ******************************************************************************/ |
| DdNode * extraTransferPermuteTime( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute, int TimeOut ) |
| { |
| DdNode *res; |
| st__table *table = NULL; |
| st__generator *gen = NULL; |
| DdNode *key, *value; |
| |
| table = st__init_table( st__ptrcmp, st__ptrhash ); |
| if ( table == NULL ) |
| goto failure; |
| res = extraTransferPermuteRecurTime( ddS, ddD, f, table, Permute, TimeOut ); |
| if ( res != NULL ) |
| cuddRef( res ); |
| |
| /* Dereference all elements in the table and dispose of the table. |
| ** This must be done also if res is NULL to avoid leaks in case of |
| ** reordering. */ |
| gen = st__init_gen( table ); |
| if ( gen == NULL ) |
| goto failure; |
| while ( st__gen( gen, ( const char ** ) &key, ( char ** ) &value ) ) |
| { |
| Cudd_RecursiveDeref( ddD, value ); |
| } |
| st__free_gen( gen ); |
| gen = NULL; |
| st__free_table( table ); |
| table = NULL; |
| |
| if ( res != NULL ) |
| cuddDeref( res ); |
| return ( res ); |
| |
| failure: |
| if ( table != NULL ) |
| st__free_table( table ); |
| if ( gen != NULL ) |
| st__free_gen( gen ); |
| return ( NULL ); |
| |
| } /* end of extraTransferPermuteTime */ |
| |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Performs the recursive step of Extra_TransferPermute.] |
| |
| Description [Performs the recursive step of Extra_TransferPermute. |
| Returns a pointer to the result if successful; NULL otherwise.] |
| |
| SideEffects [None] |
| |
| SeeAlso [extraTransferPermuteTime] |
| |
| ******************************************************************************/ |
| static DdNode * |
| extraTransferPermuteRecurTime( |
| DdManager * ddS, |
| DdManager * ddD, |
| DdNode * f, |
| st__table * table, |
| int * Permute, |
| int TimeOut ) |
| { |
| DdNode *ft, *fe, *t, *e, *var, *res; |
| DdNode *one, *zero; |
| int index; |
| int comple = 0; |
| |
| statLine( ddD ); |
| one = DD_ONE( ddD ); |
| comple = Cudd_IsComplement( f ); |
| |
| /* Trivial cases. */ |
| if ( Cudd_IsConstant( f ) ) |
| return ( Cudd_NotCond( one, comple ) ); |
| |
| |
| /* Make canonical to increase the utilization of the cache. */ |
| f = Cudd_NotCond( f, comple ); |
| /* Now f is a regular pointer to a non-constant node. */ |
| |
| /* Check the cache. */ |
| if ( st__lookup( table, ( char * ) f, ( char ** ) &res ) ) |
| return ( Cudd_NotCond( res, comple ) ); |
| |
| if ( TimeOut && Abc_Clock() > TimeOut ) |
| return NULL; |
| |
| /* Recursive step. */ |
| if ( Permute ) |
| index = Permute[f->index]; |
| else |
| index = f->index; |
| |
| ft = cuddT( f ); |
| fe = cuddE( f ); |
| |
| t = extraTransferPermuteRecurTime( ddS, ddD, ft, table, Permute, TimeOut ); |
| if ( t == NULL ) |
| { |
| return ( NULL ); |
| } |
| cuddRef( t ); |
| |
| e = extraTransferPermuteRecurTime( ddS, ddD, fe, table, Permute, TimeOut ); |
| if ( e == NULL ) |
| { |
| Cudd_RecursiveDeref( ddD, t ); |
| return ( NULL ); |
| } |
| cuddRef( e ); |
| |
| zero = Cudd_Not(ddD->one); |
| var = cuddUniqueInter( ddD, index, one, zero ); |
| if ( var == NULL ) |
| { |
| Cudd_RecursiveDeref( ddD, t ); |
| Cudd_RecursiveDeref( ddD, e ); |
| return ( NULL ); |
| } |
| res = cuddBddIteRecur( ddD, var, t, e ); |
| |
| if ( res == NULL ) |
| { |
| Cudd_RecursiveDeref( ddD, t ); |
| Cudd_RecursiveDeref( ddD, e ); |
| return ( NULL ); |
| } |
| cuddRef( res ); |
| Cudd_RecursiveDeref( ddD, t ); |
| Cudd_RecursiveDeref( ddD, e ); |
| |
| if ( st__add_direct( table, ( char * ) f, ( char * ) res ) == |
| st__OUT_OF_MEM ) |
| { |
| Cudd_RecursiveDeref( ddD, res ); |
| return ( NULL ); |
| } |
| return ( Cudd_NotCond( res, comple ) ); |
| |
| } /* end of extraTransferPermuteRecurTime */ |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| ABC_NAMESPACE_IMPL_END |
| |