You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							660 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							660 lines
						
					
					
						
							18 KiB
						
					
					
				
								/**
							 | 
						|
								  @file
							 | 
						|
								
							 | 
						|
								  @ingroup cudd
							 | 
						|
								
							 | 
						|
								  @brief Returns a subset of minterms from a boolean function.
							 | 
						|
								
							 | 
						|
								  @author Balakrishna Kumthekar
							 | 
						|
								
							 | 
						|
								  @copyright@parblock
							 | 
						|
								  Copyright (c) 1995-2015, 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.
							 | 
						|
								  @endparblock
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								
							 | 
						|
								#include "util.h"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Structure declarations                                                    */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/** \cond */
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* 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);
							 | 
						|
								
							 | 
						|
								/** \endcond */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Returns m minterms from a %BDD.
							 | 
						|
								
							 | 
						|
								  @details 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>.
							 | 
						|
								
							 | 
						|
								  @return a %BDD with <code>m</code> minterms of the on-set of S if
							 | 
						|
								  successful; NULL otherwise.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								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 = 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) {
							 | 
						|
										FREE(varSeen);
							 | 
						|
										return(S);
							 | 
						|
									    }
							 | 
						|
									    result = selectMintermsFromUniverse(manager,varSeen,m);
							 | 
						|
									    if (result)
							 | 
						|
										cuddRef(result);
							 | 
						|
									    FREE(varSeen);
							 | 
						|
									} else {
							 | 
						|
									    mtable = st_init_table(st_ptrcmp,st_ptrhash);
							 | 
						|
									    if (mtable == NULL) {
							 | 
						|
										(void) fprintf(manager->out,
							 | 
						|
											       "Cudd_SplitSet: out-of-memory.\n");
							 | 
						|
										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(void));
							 | 
						|
										st_free_table(mtable);
							 | 
						|
										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);
							 | 
						|
									    FREE(varSeen);
							 | 
						|
									}
							 | 
						|
								    } while (manager->reordered == 1);
							 | 
						|
								    if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) {
							 | 
						|
								        manager->timeoutHandler(manager, manager->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    cuddDeref(result);
							 | 
						|
								    return(result);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SplitSet */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Implements the recursive step of Cudd_SplitSet.
							 | 
						|
								
							 | 
						|
								  @details 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.
							 | 
						|
								
							 | 
						|
								  @sideeffect The array 'varSeen' is updated at every recursive call
							 | 
						|
								  to set the variables traversed by the procedure.
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								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_IsConstantInt(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_IsConstantInt(Nv) && Cudd_IsConstantInt(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_IsConstantInt(Nv)) {
							 | 
						|
								      if (!st_lookup(mtable, Nv, (void **) &dummy)) return(NULL);
							 | 
						|
									numT = *dummy/(2*(1U<<index));
							 | 
						|
								    } else if (Nv == one) {
							 | 
						|
									numT = max/(2*(1U<<index));
							 | 
						|
								    } else {
							 | 
						|
									numT = 0;
							 | 
						|
								    }
							 | 
						|
								  
							 | 
						|
								    if (!Cudd_IsConstantInt(Nnv)) {
							 | 
						|
								      if (!st_lookup(mtable, Nnv, (void **) &dummy)) return(NULL);
							 | 
						|
									numE = *dummy/(2*(1U<<index));
							 | 
						|
								    } else if (Nnv == one) {
							 | 
						|
									numE = max/(2*(1U<<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_IsConstantInt(Nv) && !Cudd_IsConstantInt(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_IsConstantInt(Nv) && Cudd_IsConstantInt(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                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief This function prepares an array of variables which have not been
							 | 
						|
								  encountered so far when traversing the procedure cuddSplitSetRecur.
							 | 
						|
								
							 | 
						|
								  @details 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 at most log(n).
							 | 
						|
								
							 | 
						|
								  @sideeffect 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 = 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]);
							 | 
						|
								    FREE(vars);
							 | 
						|
								
							 | 
						|
								    return(result);
							 | 
						|
								
							 | 
						|
								} /* end of selectMintermsFromUniverse */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Recursive procedure to extract n mintems from constant 1.
							 | 
						|
								
							 | 
						|
								  @sideeffect 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 */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Annotates every node in the %BDD node with its minterm count.
							 | 
						|
								
							 | 
						|
								  @details In this function, every node and the minterm count
							 | 
						|
								  represented by it are stored in a hash table.
							 | 
						|
								
							 | 
						|
								  @sideeffect 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;
							 | 
						|
								    double min_v,min_nv;
							 | 
						|
								    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, node, (void **) &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 = ALLOC(double,1);
							 | 
						|
								    if (pmin == NULL) {
							 | 
						|
									manager->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return((double)CUDD_OUT_OF_MEM);
							 | 
						|
								    }
							 | 
						|
								    *pmin = min_N;
							 | 
						|
								
							 | 
						|
								    if (st_insert(table, node, pmin) == ST_OUT_OF_MEM) {
							 | 
						|
									FREE(pmin);
							 | 
						|
									return((double)CUDD_OUT_OF_MEM);
							 | 
						|
								    }
							 | 
						|
								    
							 | 
						|
								    return(min_N);
							 | 
						|
								
							 | 
						|
								} /* end of bddAnnotateMintermCount */
							 |