| /**CFile*********************************************************************** |
| |
| FileName [cuddSplit.c] |
| |
| PackageName [cudd] |
| |
| Synopsis [Returns a subset of minterms from a boolean function.] |
| |
| Description [External functions included in this modoule: |
| <ul> |
| <li> Cudd_SplitSet() |
| </ul> |
| Internal functions included in this module: |
| <ul> |
| <li> cuddSplitSetRecur() |
| </u> |
| Static functions included in this module: |
| <ul> |
| <li> selectMintermsFromUniverse() |
| <li> mintermsFromUniverse() |
| <li> bddAnnotateMintermCount() |
| </ul> ] |
| |
| SeeAlso [] |
| |
| Author [Balakrishna Kumthekar] |
| |
| Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado |
| |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| Neither the name of the University of Colorado nor the names of its |
| contributors may be used to endorse or promote products derived from |
| this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| POSSIBILITY OF SUCH DAMAGE.] |
| |
| ******************************************************************************/ |
| |
| #include "misc/util/util_hack.h" |
| #include "cuddInt.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Constant declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Type declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Structure declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Variable declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Macro declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /**AutomaticStart*************************************************************/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Static function prototypes */ |
| /*---------------------------------------------------------------------------*/ |
| |
| static DdNode * selectMintermsFromUniverse (DdManager *manager, int *varSeen, double n); |
| static DdNode * mintermsFromUniverse (DdManager *manager, DdNode **vars, int numVars, double n, int index); |
| static double bddAnnotateMintermCount (DdManager *manager, DdNode *node, double max, st__table *table); |
| |
| /**AutomaticEnd***************************************************************/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of exported functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Returns m minterms from a BDD.] |
| |
| Description [Returns <code>m</code> minterms from a BDD whose |
| support has <code>n</code> variables at most. The procedure tries |
| to create as few extra nodes as possible. The function represented |
| by <code>S</code> depends on at most <code>n</code> of the variables |
| in <code>xVars</code>. Returns a BDD with <code>m</code> minterms |
| of the on-set of S if successful; NULL otherwise.] |
| |
| SideEffects [None] |
| |
| SeeAlso [] |
| |
| ******************************************************************************/ |
| DdNode * |
| Cudd_SplitSet( |
| DdManager * manager, |
| DdNode * S, |
| DdNode ** xVars, |
| int n, |
| double m) |
| { |
| DdNode *result; |
| DdNode *zero, *one; |
| double max, num; |
| st__table *mtable; |
| int *varSeen; |
| int i,index, size; |
| |
| size = manager->size; |
| one = DD_ONE(manager); |
| zero = Cudd_Not(one); |
| |
| /* Trivial cases. */ |
| if (m == 0.0) { |
| return(zero); |
| } |
| if (S == zero) { |
| return(NULL); |
| } |
| |
| max = pow(2.0,(double)n); |
| if (m > max) |
| return(NULL); |
| |
| do { |
| manager->reordered = 0; |
| /* varSeen is used to mark the variables that are encountered |
| ** while traversing the BDD S. |
| */ |
| varSeen = ABC_ALLOC(int, size); |
| if (varSeen == NULL) { |
| manager->errorCode = CUDD_MEMORY_OUT; |
| return(NULL); |
| } |
| for (i = 0; i < size; i++) { |
| varSeen[i] = -1; |
| } |
| for (i = 0; i < n; i++) { |
| index = (xVars[i])->index; |
| varSeen[manager->invperm[index]] = 0; |
| } |
| |
| if (S == one) { |
| if (m == max) { |
| ABC_FREE(varSeen); |
| return(S); |
| } |
| result = selectMintermsFromUniverse(manager,varSeen,m); |
| if (result) |
| cuddRef(result); |
| ABC_FREE(varSeen); |
| } else { |
| mtable = st__init_table( st__ptrcmp, st__ptrhash); |
| if (mtable == NULL) { |
| (void) fprintf(manager->out, |
| "Cudd_SplitSet: out-of-memory.\n"); |
| ABC_FREE(varSeen); |
| manager->errorCode = CUDD_MEMORY_OUT; |
| return(NULL); |
| } |
| /* The nodes of BDD S are annotated by the number of minterms |
| ** in their onset. The node and the number of minterms in its |
| ** onset are stored in mtable. |
| */ |
| num = bddAnnotateMintermCount(manager,S,max,mtable); |
| if (m == num) { |
| st__foreach(mtable,cuddStCountfree,NIL(char)); |
| st__free_table(mtable); |
| ABC_FREE(varSeen); |
| return(S); |
| } |
| |
| result = cuddSplitSetRecur(manager,mtable,varSeen,S,m,max,0); |
| if (result) |
| cuddRef(result); |
| st__foreach(mtable,cuddStCountfree,NULL); |
| st__free_table(mtable); |
| ABC_FREE(varSeen); |
| } |
| } while (manager->reordered == 1); |
| |
| cuddDeref(result); |
| return(result); |
| |
| } /* end of Cudd_SplitSet */ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of internal functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Implements the recursive step of Cudd_SplitSet.] |
| |
| Description [Implements the recursive step of Cudd_SplitSet. The |
| procedure recursively traverses the BDD and checks to see if any |
| node satisfies the minterm requirements as specified by 'n'. At any |
| node X, n is compared to the number of minterms in the onset of X's |
| children. If either of the child nodes have exactly n minterms, then |
| that node is returned; else, if n is greater than the onset of one |
| of the child nodes, that node is retained and the difference in the |
| number of minterms is extracted from the other child. In case n |
| minterms can be extracted from constant 1, the algorithm returns the |
| result with at most log(n) nodes.] |
| |
| SideEffects [The array 'varSeen' is updated at every recursive call |
| to set the variables traversed by the procedure.] |
| |
| SeeAlso [] |
| |
| ******************************************************************************/ |
| DdNode* |
| cuddSplitSetRecur( |
| DdManager * manager, |
| st__table * mtable, |
| int * varSeen, |
| DdNode * p, |
| double n, |
| double max, |
| int index) |
| { |
| DdNode *one, *zero, *N, *Nv; |
| DdNode *Nnv, *q, *r, *v; |
| DdNode *result; |
| double *dummy, numT, numE; |
| int variable, positive; |
| |
| statLine(manager); |
| one = DD_ONE(manager); |
| zero = Cudd_Not(one); |
| |
| /* If p is constant, extract n minterms from constant 1. The procedure by |
| ** construction guarantees that minterms will not be extracted from |
| ** constant 0. |
| */ |
| if (Cudd_IsConstant(p)) { |
| q = selectMintermsFromUniverse(manager,varSeen,n); |
| return(q); |
| } |
| |
| N = Cudd_Regular(p); |
| |
| /* Set variable as seen. */ |
| variable = N->index; |
| varSeen[manager->invperm[variable]] = -1; |
| |
| Nv = cuddT(N); |
| Nnv = cuddE(N); |
| if (Cudd_IsComplement(p)) { |
| Nv = Cudd_Not(Nv); |
| Nnv = Cudd_Not(Nnv); |
| } |
| |
| /* If both the children of 'p' are constants, extract n minterms from a |
| ** constant node. |
| */ |
| if (Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) { |
| q = selectMintermsFromUniverse(manager,varSeen,n); |
| if (q == NULL) { |
| return(NULL); |
| } |
| cuddRef(q); |
| r = cuddBddAndRecur(manager,p,q); |
| if (r == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| return(NULL); |
| } |
| cuddRef(r); |
| Cudd_RecursiveDeref(manager,q); |
| cuddDeref(r); |
| return(r); |
| } |
| |
| /* Lookup the # of minterms in the onset of the node from the table. */ |
| if (!Cudd_IsConstant(Nv)) { |
| if (! st__lookup(mtable, (const char *)Nv, (char **)&dummy)) return(NULL); |
| numT = *dummy/(2*(1<<index)); |
| } else if (Nv == one) { |
| numT = max/(2*(1<<index)); |
| } else { |
| numT = 0; |
| } |
| |
| if (!Cudd_IsConstant(Nnv)) { |
| if (! st__lookup(mtable, (const char *)Nnv, (char **)&dummy)) return(NULL); |
| numE = *dummy/(2*(1<<index)); |
| } else if (Nnv == one) { |
| numE = max/(2*(1<<index)); |
| } else { |
| numE = 0; |
| } |
| |
| v = cuddUniqueInter(manager,variable,one,zero); |
| cuddRef(v); |
| |
| /* If perfect match. */ |
| if (numT == n) { |
| q = cuddBddAndRecur(manager,v,Nv); |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(q); |
| return(q); |
| } |
| if (numE == n) { |
| q = cuddBddAndRecur(manager,Cudd_Not(v),Nnv); |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(q); |
| return(q); |
| } |
| /* If n is greater than numT, extract the difference from the ELSE child |
| ** and retain the function represented by the THEN branch. |
| */ |
| if (numT < n) { |
| q = cuddSplitSetRecur(manager,mtable,varSeen, |
| Nnv,(n-numT),max,index+1); |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| r = cuddBddIteRecur(manager,v,Nv,q); |
| if (r == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(r); |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(r); |
| return(r); |
| } |
| /* If n is greater than numE, extract the difference from the THEN child |
| ** and retain the function represented by the ELSE branch. |
| */ |
| if (numE < n) { |
| q = cuddSplitSetRecur(manager,mtable,varSeen, |
| Nv, (n-numE),max,index+1); |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| r = cuddBddIteRecur(manager,v,q,Nnv); |
| if (r == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(r); |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(r); |
| return(r); |
| } |
| |
| /* None of the above cases; (n < numT and n < numE) and either of |
| ** the Nv, Nnv or both are not constants. If possible extract the |
| ** required minterms the constant branch. |
| */ |
| if (Cudd_IsConstant(Nv) && !Cudd_IsConstant(Nnv)) { |
| q = selectMintermsFromUniverse(manager,varSeen,n); |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| result = cuddBddAndRecur(manager,v,q); |
| if (result == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(result); |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(result); |
| return(result); |
| } else if (!Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) { |
| q = selectMintermsFromUniverse(manager,varSeen,n); |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| result = cuddBddAndRecur(manager,Cudd_Not(v),q); |
| if (result == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(result); |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(result); |
| return(result); |
| } |
| |
| /* Both Nv and Nnv are not constants. So choose the one which |
| ** has fewer minterms in its onset. |
| */ |
| positive = 0; |
| if (numT < numE) { |
| q = cuddSplitSetRecur(manager,mtable,varSeen, |
| Nv,n,max,index+1); |
| positive = 1; |
| } else { |
| q = cuddSplitSetRecur(manager,mtable,varSeen, |
| Nnv,n,max,index+1); |
| } |
| |
| if (q == NULL) { |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(q); |
| |
| if (positive) { |
| result = cuddBddAndRecur(manager,v,q); |
| } else { |
| result = cuddBddAndRecur(manager,Cudd_Not(v),q); |
| } |
| if (result == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| return(NULL); |
| } |
| cuddRef(result); |
| Cudd_RecursiveDeref(manager,q); |
| Cudd_RecursiveDeref(manager,v); |
| cuddDeref(result); |
| |
| return(result); |
| |
| } /* end of cuddSplitSetRecur */ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of static functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**Function******************************************************************** |
| |
| Synopsis [This function prepares an array of variables which have not been |
| encountered so far when traversing the procedure cuddSplitSetRecur.] |
| |
| Description [This function prepares an array of variables which have not been |
| encountered so far when traversing the procedure cuddSplitSetRecur. This |
| array is then used to extract the required number of minterms from a constant |
| 1. The algorithm guarantees that the size of BDD will be utmost \log(n).] |
| |
| SideEffects [None] |
| |
| ******************************************************************************/ |
| static DdNode * |
| selectMintermsFromUniverse( |
| DdManager * manager, |
| int * varSeen, |
| double n) |
| { |
| int numVars; |
| int i, size, j; |
| DdNode *one, *zero, *result; |
| DdNode **vars; |
| |
| numVars = 0; |
| size = manager->size; |
| one = DD_ONE(manager); |
| zero = Cudd_Not(one); |
| |
| /* Count the number of variables not encountered so far in procedure |
| ** cuddSplitSetRecur. |
| */ |
| for (i = size-1; i >= 0; i--) { |
| if(varSeen[i] == 0) |
| numVars++; |
| } |
| vars = ABC_ALLOC(DdNode *, numVars); |
| if (!vars) { |
| manager->errorCode = CUDD_MEMORY_OUT; |
| return(NULL); |
| } |
| |
| j = 0; |
| for (i = size-1; i >= 0; i--) { |
| if(varSeen[i] == 0) { |
| vars[j] = cuddUniqueInter(manager,manager->perm[i],one,zero); |
| cuddRef(vars[j]); |
| j++; |
| } |
| } |
| |
| /* Compute a function which has n minterms and depends on at most |
| ** numVars variables. |
| */ |
| result = mintermsFromUniverse(manager,vars,numVars,n, 0); |
| if (result) |
| cuddRef(result); |
| |
| for (i = 0; i < numVars; i++) |
| Cudd_RecursiveDeref(manager,vars[i]); |
| ABC_FREE(vars); |
| |
| return(result); |
| |
| } /* end of selectMintermsFromUniverse */ |
| |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Recursive procedure to extract n mintems from constant 1.] |
| |
| Description [Recursive procedure to extract n mintems from constant 1.] |
| |
| SideEffects [None] |
| |
| ******************************************************************************/ |
| static DdNode * |
| mintermsFromUniverse( |
| DdManager * manager, |
| DdNode ** vars, |
| int numVars, |
| double n, |
| int index) |
| { |
| DdNode *one, *zero; |
| DdNode *q, *result; |
| double max, max2; |
| |
| statLine(manager); |
| one = DD_ONE(manager); |
| zero = Cudd_Not(one); |
| |
| max = pow(2.0, (double)numVars); |
| max2 = max / 2.0; |
| |
| if (n == max) |
| return(one); |
| if (n == 0.0) |
| return(zero); |
| /* if n == 2^(numVars-1), return a single variable */ |
| if (n == max2) |
| return vars[index]; |
| else if (n > max2) { |
| /* When n > 2^(numVars-1), a single variable vars[index] |
| ** contains 2^(numVars-1) minterms. The rest are extracted |
| ** from a constant with 1 less variable. |
| */ |
| q = mintermsFromUniverse(manager,vars,numVars-1,(n-max2),index+1); |
| if (q == NULL) |
| return(NULL); |
| cuddRef(q); |
| result = cuddBddIteRecur(manager,vars[index],one,q); |
| } else { |
| /* When n < 2^(numVars-1), a literal of variable vars[index] |
| ** is selected. The required n minterms are extracted from a |
| ** constant with 1 less variable. |
| */ |
| q = mintermsFromUniverse(manager,vars,numVars-1,n,index+1); |
| if (q == NULL) |
| return(NULL); |
| cuddRef(q); |
| result = cuddBddAndRecur(manager,vars[index],q); |
| } |
| |
| if (result == NULL) { |
| Cudd_RecursiveDeref(manager,q); |
| return(NULL); |
| } |
| cuddRef(result); |
| Cudd_RecursiveDeref(manager,q); |
| cuddDeref(result); |
| return(result); |
| |
| } /* end of mintermsFromUniverse */ |
| |
| |
| /**Function******************************************************************** |
| |
| Synopsis [Annotates every node in the BDD node with its minterm count.] |
| |
| Description [Annotates every node in the BDD node with its minterm count. |
| In this function, every node and the minterm count represented by it are |
| stored in a hash table.] |
| |
| SideEffects [Fills up 'table' with the pair <node,minterm_count>.] |
| |
| ******************************************************************************/ |
| static double |
| bddAnnotateMintermCount( |
| DdManager * manager, |
| DdNode * node, |
| double max, |
| st__table * table) |
| { |
| |
| DdNode *N,*Nv,*Nnv; |
| register double min_v,min_nv; |
| register double min_N; |
| double *pmin; |
| double *dummy; |
| |
| statLine(manager); |
| N = Cudd_Regular(node); |
| if (cuddIsConstant(N)) { |
| if (node == DD_ONE(manager)) { |
| return(max); |
| } else { |
| return(0.0); |
| } |
| } |
| |
| if ( st__lookup(table, (const char *)node, (char **)&dummy)) { |
| return(*dummy); |
| } |
| |
| Nv = cuddT(N); |
| Nnv = cuddE(N); |
| if (N != node) { |
| Nv = Cudd_Not(Nv); |
| Nnv = Cudd_Not(Nnv); |
| } |
| |
| /* Recur on the two branches. */ |
| min_v = bddAnnotateMintermCount(manager,Nv,max,table) / 2.0; |
| if (min_v == (double)CUDD_OUT_OF_MEM) |
| return ((double)CUDD_OUT_OF_MEM); |
| min_nv = bddAnnotateMintermCount(manager,Nnv,max,table) / 2.0; |
| if (min_nv == (double)CUDD_OUT_OF_MEM) |
| return ((double)CUDD_OUT_OF_MEM); |
| min_N = min_v + min_nv; |
| |
| pmin = ABC_ALLOC(double,1); |
| if (pmin == NULL) { |
| manager->errorCode = CUDD_MEMORY_OUT; |
| return((double)CUDD_OUT_OF_MEM); |
| } |
| *pmin = min_N; |
| |
| if ( st__insert(table,(char *)node, (char *)pmin) == st__OUT_OF_MEM) { |
| ABC_FREE(pmin); |
| return((double)CUDD_OUT_OF_MEM); |
| } |
| |
| return(min_N); |
| |
| } /* end of bddAnnotateMintermCount */ |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |