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.
		
		
		
		
		
			
		
			
				
					
					
						
							2131 lines
						
					
					
						
							58 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							2131 lines
						
					
					
						
							58 KiB
						
					
					
				| /** | |
|   @file | |
|  | |
|   @ingroup cudd | |
|  | |
|   @brief Functions for %BDD decomposition. | |
|  | |
|   @author Kavita Ravi, Fabio Somenzi | |
|  | |
|   @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                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| #define DEPTH 5 | |
| #define THRESHOLD 10 | |
| #define NONE 0 | |
| #define PAIR_ST 1 | |
| #define PAIR_CR 2 | |
| #define G_ST 3 | |
| #define G_CR 4 | |
| #define H_ST 5 | |
| #define H_CR 6 | |
| #define BOTH_G 7 | |
| #define BOTH_H 8 | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| /** | |
|  * @brief Type of a pair of conjoined BDDs. | |
|  */ | |
| typedef struct Conjuncts { | |
|     DdNode *g; | |
|     DdNode *h; | |
| } Conjuncts; | |
| 
 | |
| /** | |
|    @brief Stats for one node. | |
| */ | |
| typedef struct  NodeStat { | |
|     int distance; | |
|     int localRef; | |
| } NodeStat; | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| #define FactorsNotStored(factors)  ((int)((ptrint)(factors) & 01)) | |
|  | |
| #define FactorsComplement(factors) ((Conjuncts *)((ptrint)(factors) | 01)) | |
|  | |
| #define FactorsUncomplement(factors) ((Conjuncts *)((ptrint)(factors) ^ 01)) | |
|  | |
| /** \cond */ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static NodeStat * CreateBotDist (DdNode * node, st_table * distanceTable); | |
| static double CountMinterms (DdManager * dd, DdNode * node, double max, st_table * mintermTable, FILE *fp); | |
| static void ConjunctsFree (DdManager * dd, Conjuncts * factors); | |
| static int PairInTables (DdNode * g, DdNode * h, st_table * ghTable); | |
| static Conjuncts * CheckTablesCacheAndReturn (DdManager *manager, DdNode * node, DdNode * g, DdNode * h, st_table * ghTable, st_table * cacheTable); | |
| static Conjuncts * PickOnePair (DdManager * manager, DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable); | |
| static Conjuncts * CheckInTables (DdManager * manager, DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable, int * outOfMem); | |
| static Conjuncts * ZeroCase (DdManager * dd, DdNode * node, Conjuncts * factorsNv, st_table * ghTable, st_table * cacheTable, int switched); | |
| static Conjuncts * BuildConjuncts (DdManager * dd, DdNode * node, st_table * distanceTable, st_table * cacheTable, int approxDistance, int maxLocalRef, st_table * ghTable, st_table * mintermTable, int32_t *lastTimeG); | |
| static int cuddConjunctsAux (DdManager * dd, DdNode * f, DdNode ** c1, DdNode ** c2); | |
| 
 | |
| /** \endcond */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way conjunctive decomposition of a %BDD. | |
|  | |
|   @details This procedure owes its name to the use of supersetting to | |
|   obtain an initial factor of the given function.  The conjuncts | |
|   produced by this procedure tend to be imbalanced. | |
|  | |
|   @return the number of conjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The factors are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the conjuncts are already | |
|   referenced. If the function returns 0, the array for the conjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddApproxDisjDecomp Cudd_bddIterConjDecomp | |
|   Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox | |
|   Cudd_bddSqueeze Cudd_bddLICompaction | |
|  | |
| */ | |
| int | |
| Cudd_bddApproxConjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** conjuncts /**< address of the first factor */) | |
| { | |
|     DdNode *superset1, *superset2, *glocal, *hlocal; | |
|     int nvars = Cudd_SupportSize(dd,f); | |
| 
 | |
|     /* Find a tentative first factor by overapproximation and minimization. */ | |
|     superset1 = Cudd_RemapOverApprox(dd,f,nvars,0,1.0); | |
|     if (superset1 == NULL) return(0); | |
|     cuddRef(superset1); | |
|     superset2 = Cudd_bddSqueeze(dd,f,superset1); | |
|     if (superset2 == NULL) { | |
| 	Cudd_RecursiveDeref(dd,superset1); | |
| 	return(0); | |
|     } | |
|     cuddRef(superset2); | |
|     Cudd_RecursiveDeref(dd,superset1); | |
| 
 | |
|     /* Compute the second factor by minimization. */ | |
|     hlocal = Cudd_bddLICompaction(dd,f,superset2); | |
|     if (hlocal == NULL) { | |
| 	Cudd_RecursiveDeref(dd,superset2); | |
| 	return(0); | |
|     } | |
|     cuddRef(hlocal); | |
| 
 | |
|     /* Refine the first factor by minimization. If h turns out to be f, this | |
|     ** step guarantees that g will be 1. */ | |
|     glocal = Cudd_bddLICompaction(dd,superset2,hlocal); | |
|     if (glocal == NULL) { | |
| 	Cudd_RecursiveDeref(dd,superset2); | |
| 	Cudd_RecursiveDeref(dd,hlocal); | |
| 	return(0); | |
|     } | |
|     cuddRef(glocal); | |
|     Cudd_RecursiveDeref(dd,superset2); | |
| 
 | |
|     if (glocal != DD_ONE(dd)) { | |
| 	if (hlocal != DD_ONE(dd)) { | |
| 	    *conjuncts = ALLOC(DdNode *,2); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,glocal); | |
| 		Cudd_RecursiveDeref(dd,hlocal); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = glocal; | |
| 	    (*conjuncts)[1] = hlocal; | |
| 	    return(2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd,hlocal); | |
| 	    *conjuncts = ALLOC(DdNode *,1); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,glocal); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = glocal; | |
| 	    return(1); | |
| 	} | |
|     } else { | |
| 	Cudd_RecursiveDeref(dd,glocal); | |
| 	*conjuncts = ALLOC(DdNode *,1); | |
| 	if (*conjuncts == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,hlocal); | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(0); | |
| 	} | |
| 	(*conjuncts)[0] = hlocal; | |
| 	return(1); | |
|     } | |
| 
 | |
| } /* end of Cudd_bddApproxConjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way disjunctive decomposition of a %BDD. | |
|  | |
|   @details The disjuncts produced by this procedure tend to be | |
|   imbalanced. | |
|  | |
|   @return the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The two disjuncts are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the disjuncts are already | |
|   referenced. If the function returns 0, the array for the disjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddApproxConjDecomp Cudd_bddIterDisjDecomp | |
|   Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp | |
|  | |
| */ | |
| int | |
| Cudd_bddApproxDisjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** disjuncts /**< address of the array of the disjuncts */) | |
| { | |
|     int result, i; | |
| 
 | |
|     result = Cudd_bddApproxConjDecomp(dd,Cudd_Not(f),disjuncts); | |
|     for (i = 0; i < result; i++) { | |
| 	(*disjuncts)[i] = Cudd_Not((*disjuncts)[i]); | |
|     } | |
|     return(result); | |
| 
 | |
| } /* end of Cudd_bddApproxDisjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way conjunctive decomposition of a %BDD. | |
|  | |
|   @details This procedure owes its name to the iterated use of | |
|   supersetting to obtain a factor of the given function.  The | |
|   conjuncts produced by this procedure tend to be imbalanced. | |
|  | |
|   @return the number of conjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The factors are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the conjuncts are already | |
|   referenced. If the function returns 0, the array for the conjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddIterDisjDecomp Cudd_bddApproxConjDecomp | |
|   Cudd_bddGenConjDecomp Cudd_bddVarConjDecomp Cudd_RemapOverApprox | |
|   Cudd_bddSqueeze Cudd_bddLICompaction | |
|  | |
| */ | |
| int | |
| Cudd_bddIterConjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** conjuncts /**< address of the array of conjuncts */) | |
| { | |
|     DdNode *superset1, *superset2, *old[2], *res[2]; | |
|     int sizeOld, sizeNew; | |
|     int nvars = Cudd_SupportSize(dd,f); | |
| 
 | |
|     old[0] = DD_ONE(dd); | |
|     cuddRef(old[0]); | |
|     old[1] = f; | |
|     cuddRef(old[1]); | |
|     sizeOld = Cudd_SharingSize(old,2); | |
| 
 | |
|     do { | |
| 	/* Find a tentative first factor by overapproximation and | |
| 	** minimization. */ | |
| 	superset1 = Cudd_RemapOverApprox(dd,old[1],nvars,0,1.0); | |
| 	if (superset1 == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,old[0]); | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(superset1); | |
| 	superset2 = Cudd_bddSqueeze(dd,old[1],superset1); | |
| 	if (superset2 == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,old[0]); | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    Cudd_RecursiveDeref(dd,superset1); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(superset2); | |
| 	Cudd_RecursiveDeref(dd,superset1); | |
| 	res[0] = Cudd_bddAnd(dd,old[0],superset2); | |
| 	if (res[0] == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,superset2); | |
| 	    Cudd_RecursiveDeref(dd,old[0]); | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(res[0]); | |
| 	Cudd_RecursiveDeref(dd,superset2); | |
| 	if (res[0] == old[0]) { | |
| 	    Cudd_RecursiveDeref(dd,res[0]); | |
| 	    break;	/* avoid infinite loop */ | |
| 	} | |
| 
 | |
| 	/* Compute the second factor by minimization. */ | |
| 	res[1] = Cudd_bddLICompaction(dd,old[1],res[0]); | |
| 	if (res[1] == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,old[0]); | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(res[1]); | |
| 
 | |
| 	sizeNew = Cudd_SharingSize(res,2); | |
| 	if (sizeNew <= sizeOld) { | |
| 	    Cudd_RecursiveDeref(dd,old[0]); | |
| 	    old[0] = res[0]; | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    old[1] = res[1]; | |
| 	    sizeOld = sizeNew; | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd,res[0]); | |
| 	    Cudd_RecursiveDeref(dd,res[1]); | |
| 	    break; | |
| 	} | |
| 
 | |
|     } while (1); | |
| 
 | |
|     /* Refine the first factor by minimization. If h turns out to | |
|     ** be f, this step guarantees that g will be 1. */ | |
|     superset1 = Cudd_bddLICompaction(dd,old[0],old[1]); | |
|     if (superset1 == NULL) { | |
| 	Cudd_RecursiveDeref(dd,old[0]); | |
| 	Cudd_RecursiveDeref(dd,old[1]); | |
| 	return(0); | |
|     } | |
|     cuddRef(superset1); | |
|     Cudd_RecursiveDeref(dd,old[0]); | |
|     old[0] = superset1; | |
| 
 | |
|     if (old[0] != DD_ONE(dd)) { | |
| 	if (old[1] != DD_ONE(dd)) { | |
| 	    *conjuncts = ALLOC(DdNode *,2); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,old[0]); | |
| 		Cudd_RecursiveDeref(dd,old[1]); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = old[0]; | |
| 	    (*conjuncts)[1] = old[1]; | |
| 	    return(2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    *conjuncts = ALLOC(DdNode *,1); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,old[0]); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = old[0]; | |
| 	    return(1); | |
| 	} | |
|     } else { | |
| 	Cudd_RecursiveDeref(dd,old[0]); | |
| 	*conjuncts = ALLOC(DdNode *,1); | |
| 	if (*conjuncts == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,old[1]); | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(0); | |
| 	} | |
| 	(*conjuncts)[0] = old[1]; | |
| 	return(1); | |
|     } | |
| 
 | |
| } /* end of Cudd_bddIterConjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way disjunctive decomposition of a %BDD. | |
|  | |
|   @details The disjuncts produced by this procedure tend to be | |
|   imbalanced. | |
|  | |
|   @return the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The two disjuncts are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the disjuncts are already | |
|   referenced. If the function returns 0, the array for the disjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddIterConjDecomp Cudd_bddApproxDisjDecomp | |
|   Cudd_bddGenDisjDecomp Cudd_bddVarDisjDecomp | |
|  | |
| */ | |
| int | |
| Cudd_bddIterDisjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** disjuncts /**< address of the array of the disjuncts */) | |
| { | |
|     int result, i; | |
| 
 | |
|     result = Cudd_bddIterConjDecomp(dd,Cudd_Not(f),disjuncts); | |
|     for (i = 0; i < result; i++) { | |
| 	(*disjuncts)[i] = Cudd_Not((*disjuncts)[i]); | |
|     } | |
|     return(result); | |
| 
 | |
| } /* end of Cudd_bddIterDisjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way conjunctive decomposition of a %BDD. | |
|  | |
|   @details This procedure owes its name to the fact tht it generalizes | |
|   the decomposition based on the cofactors with respect to one | |
|   variable.  The conjuncts produced by this procedure tend to be | |
|   balanced. | |
|  | |
|   @return the number of conjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The two factors are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the conjuncts are already | |
|   referenced. If the function returns 0, the array for the conjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddGenDisjDecomp Cudd_bddApproxConjDecomp | |
|   Cudd_bddIterConjDecomp Cudd_bddVarConjDecomp | |
|  | |
| */ | |
| int | |
| Cudd_bddGenConjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** conjuncts /**< address of the array of conjuncts */) | |
| { | |
|     int result; | |
|     DdNode *glocal, *hlocal; | |
| 
 | |
|     do { | |
| 	dd->reordered = 0; | |
| 	result = cuddConjunctsAux(dd, f, &glocal, &hlocal); | |
|     } while (dd->reordered == 1); | |
| 
 | |
|     if (result == 0) { | |
|         if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) { | |
|             dd->timeoutHandler(dd, dd->tohArg); | |
|         } | |
| 	return(0); | |
|     } | |
| 
 | |
|     if (glocal != DD_ONE(dd)) { | |
| 	if (hlocal != DD_ONE(dd)) { | |
| 	    *conjuncts = ALLOC(DdNode *,2); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,glocal); | |
| 		Cudd_RecursiveDeref(dd,hlocal); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = glocal; | |
| 	    (*conjuncts)[1] = hlocal; | |
| 	    return(2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd,hlocal); | |
| 	    *conjuncts = ALLOC(DdNode *,1); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,glocal); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = glocal; | |
| 	    return(1); | |
| 	} | |
|     } else { | |
| 	Cudd_RecursiveDeref(dd,glocal); | |
| 	*conjuncts = ALLOC(DdNode *,1); | |
| 	if (*conjuncts == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,hlocal); | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(0); | |
| 	} | |
| 	(*conjuncts)[0] = hlocal; | |
| 	return(1); | |
|     } | |
| 
 | |
| } /* end of Cudd_bddGenConjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way disjunctive decomposition of a %BDD. | |
|  | |
|   @details The disjuncts produced by this procedure tend to be | |
|   balanced. | |
|  | |
|   @return the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The two disjuncts are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the disjuncts are already | |
|   referenced. If the function returns 0, the array for the disjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddGenConjDecomp Cudd_bddApproxDisjDecomp | |
|   Cudd_bddIterDisjDecomp Cudd_bddVarDisjDecomp | |
|  | |
| */ | |
| int | |
| Cudd_bddGenDisjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** disjuncts /**< address of the array of the disjuncts */) | |
| { | |
|     int result, i; | |
| 
 | |
|     result = Cudd_bddGenConjDecomp(dd,Cudd_Not(f),disjuncts); | |
|     for (i = 0; i < result; i++) { | |
| 	(*disjuncts)[i] = Cudd_Not((*disjuncts)[i]); | |
|     } | |
|     return(result); | |
| 
 | |
| } /* end of Cudd_bddGenDisjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way conjunctive decomposition of a %BDD. | |
|  | |
|   @details Conjunctively decomposes one %BDD according to a | |
|   variable.  If <code>f</code> is the function of the %BDD and | |
|   <code>x</code> is the variable, the decomposition is | |
|   <code>(f+x)(f+x')</code>.  The variable is chosen so as to balance | |
|   the sizes of the two conjuncts and to keep them small. | |
|  | |
|   @return the number of conjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The two factors are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the conjuncts are already | |
|   referenced. If the function returns 0, the array for the conjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddVarDisjDecomp Cudd_bddGenConjDecomp | |
|   Cudd_bddApproxConjDecomp Cudd_bddIterConjDecomp | |
|  | |
| */ | |
| int | |
| Cudd_bddVarConjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** conjuncts /**< address of the array of conjuncts */) | |
| { | |
|     int best; | |
|     int min; | |
|     DdNode *support, *scan, *var, *glocal, *hlocal; | |
| 
 | |
|     /* Find best cofactoring variable. */ | |
|     support = Cudd_Support(dd,f); | |
|     if (support == NULL) return(0); | |
|     if (Cudd_IsConstantInt(support)) { | |
| 	*conjuncts = ALLOC(DdNode *,1); | |
| 	if (*conjuncts == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(0); | |
| 	} | |
| 	(*conjuncts)[0] = f; | |
| 	cuddRef((*conjuncts)[0]); | |
| 	return(1); | |
|     } | |
|     cuddRef(support); | |
|     min = 1000000000; | |
|     best = -1; | |
|     scan = support; | |
|     while (!Cudd_IsConstantInt(scan)) { | |
|         int i, est1, est0, est; | |
| 	i = scan->index; | |
| 	est1 = Cudd_EstimateCofactor(dd,f,i,1); | |
|         if (est1 == CUDD_OUT_OF_MEM) return(0); | |
| 	est0 = Cudd_EstimateCofactor(dd,f,i,0); | |
|         if (est0 == CUDD_OUT_OF_MEM) return(0); | |
| 	/* Minimize the size of the larger of the two cofactors. */ | |
| 	est = (est1 > est0) ? est1 : est0; | |
| 	if (est < min) { | |
| 	    min = est; | |
| 	    best = i; | |
| 	} | |
| 	scan = cuddT(scan); | |
|     } | |
| #ifdef DD_DEBUG | |
|     assert(best >= 0 && best < dd->size); | |
| #endif | |
|     Cudd_RecursiveDeref(dd,support); | |
| 
 | |
|     var = Cudd_bddIthVar(dd,best); | |
|     glocal = Cudd_bddOr(dd,f,var); | |
|     if (glocal == NULL) { | |
| 	return(0); | |
|     } | |
|     cuddRef(glocal); | |
|     hlocal = Cudd_bddOr(dd,f,Cudd_Not(var)); | |
|     if (hlocal == NULL) { | |
| 	Cudd_RecursiveDeref(dd,glocal); | |
| 	return(0); | |
|     } | |
|     cuddRef(hlocal); | |
| 
 | |
|     if (glocal != DD_ONE(dd)) { | |
| 	if (hlocal != DD_ONE(dd)) { | |
| 	    *conjuncts = ALLOC(DdNode *,2); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,glocal); | |
| 		Cudd_RecursiveDeref(dd,hlocal); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = glocal; | |
| 	    (*conjuncts)[1] = hlocal; | |
| 	    return(2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd,hlocal); | |
| 	    *conjuncts = ALLOC(DdNode *,1); | |
| 	    if (*conjuncts == NULL) { | |
| 		Cudd_RecursiveDeref(dd,glocal); | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		return(0); | |
| 	    } | |
| 	    (*conjuncts)[0] = glocal; | |
| 	    return(1); | |
| 	} | |
|     } else { | |
| 	Cudd_RecursiveDeref(dd,glocal); | |
| 	*conjuncts = ALLOC(DdNode *,1); | |
| 	if (*conjuncts == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,hlocal); | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(0); | |
| 	} | |
| 	(*conjuncts)[0] = hlocal; | |
| 	return(1); | |
|     } | |
| 
 | |
| } /* end of Cudd_bddVarConjDecomp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Performs two-way disjunctive decomposition of a %BDD. | |
|  | |
|   @details Performs two-way disjunctive decomposition of a %BDD | |
|   according to a variable. If <code>f</code> is the function of the | |
|   %BDD and <code>x</code> is the variable, the decomposition is | |
|   <code>f*x + f*x'</code>.  The variable is chosen so as to balance | |
|   the sizes of the two disjuncts and to keep them small. | |
|  | |
|   @return the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. | |
|  | |
|   @sideeffect The two disjuncts are returned in an array as side effects. | |
|   The array is allocated by this function. It is the caller's responsibility | |
|   to free it. On successful completion, the disjuncts are already | |
|   referenced. If the function returns 0, the array for the disjuncts is | |
|   not allocated. If the function returns 1, the only factor equals the | |
|   function to be decomposed. | |
|  | |
|   @see Cudd_bddVarConjDecomp Cudd_bddApproxDisjDecomp | |
|   Cudd_bddIterDisjDecomp Cudd_bddGenDisjDecomp | |
|  | |
| */ | |
| int | |
| Cudd_bddVarDisjDecomp( | |
|   DdManager * dd /**< manager */, | |
|   DdNode * f /**< function to be decomposed */, | |
|   DdNode *** disjuncts /**< address of the array of the disjuncts */) | |
| { | |
|     int result, i; | |
| 
 | |
|     result = Cudd_bddVarConjDecomp(dd,Cudd_Not(f),disjuncts); | |
|     for (i = 0; i < result; i++) { | |
| 	(*disjuncts)[i] = Cudd_Not((*disjuncts)[i]); | |
|     } | |
|     return(result); | |
| 
 | |
| } /* end of Cudd_bddVarDisjDecomp */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Get longest distance of node from constant. | |
|  | |
|   @return the distance of the root from the constant if successful; | |
|   CUDD_OUT_OF_MEM otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static NodeStat * | |
| CreateBotDist( | |
|   DdNode * node, | |
|   st_table * distanceTable) | |
| { | |
|     DdNode *N, *Nv, *Nnv; | |
|     int distance, distanceNv, distanceNnv; | |
|     NodeStat *nodeStat, *nodeStatNv, *nodeStatNnv; | |
| 
 | |
| #if 0 | |
|     if (Cudd_IsConstantInt(node)) { | |
| 	return(0); | |
|     } | |
| #endif | |
|      | |
|     /* Return the entry in the table if found. */ | |
|     N = Cudd_Regular(node); | |
|     if (st_lookup(distanceTable, N, (void **) &nodeStat)) { | |
| 	nodeStat->localRef++; | |
| 	return(nodeStat); | |
|     } | |
| 
 | |
|     Nv = cuddT(N); | |
|     Nnv = cuddE(N); | |
|     Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node)); | |
|     Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node)); | |
| 
 | |
|     /* Recur on the children. */ | |
|     nodeStatNv = CreateBotDist(Nv, distanceTable); | |
|     if (nodeStatNv == NULL) return(NULL); | |
|     distanceNv = nodeStatNv->distance; | |
| 
 | |
|     nodeStatNnv = CreateBotDist(Nnv, distanceTable); | |
|     if (nodeStatNnv == NULL) return(NULL); | |
|     distanceNnv = nodeStatNnv->distance; | |
|     /* Store max distance from constant; note sometimes this distance | |
|     ** may be to 0. | |
|     */ | |
|     distance = (distanceNv > distanceNnv) ? (distanceNv+1) : (distanceNnv + 1); | |
| 
 | |
|     nodeStat = ALLOC(NodeStat, 1); | |
|     if (nodeStat == NULL) { | |
| 	return(0); | |
|     } | |
|     nodeStat->distance = distance; | |
|     nodeStat->localRef = 1; | |
|      | |
|     if (st_insert(distanceTable, N, nodeStat) == | |
| 	ST_OUT_OF_MEM) { | |
| 	return(0); | |
| 
 | |
|     } | |
|     return(nodeStat); | |
| 
 | |
| } /* end of CreateBotDist */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Count the number of minterms of each node ina a %BDD and | |
|   store it in a hash table. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static double | |
| CountMinterms( | |
|   DdManager * dd, | |
|   DdNode * node, | |
|   double  max, | |
|   st_table * mintermTable, | |
|   FILE *fp) | |
| { | |
|     DdNode *N, *Nv, *Nnv; | |
|     double min, minNv, minNnv; | |
|     double *dummy; | |
| 
 | |
|     N = Cudd_Regular(node); | |
| 
 | |
|     if (cuddIsConstant(N)) { | |
|         if (node == Cudd_Not(DD_ONE(dd))) { | |
| 	    return(0); | |
| 	} else { | |
| 	    return(max); | |
| 	} | |
|     } | |
| 
 | |
|     /* Return the entry in the table if found. */ | |
|     if (st_lookup(mintermTable, node, (void **) &dummy)) { | |
|         min = *dummy; | |
| 	return(min); | |
|     } | |
| 
 | |
|     Nv = cuddT(N); | |
|     Nnv = cuddE(N); | |
|     Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node)); | |
|     Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node)); | |
| 
 | |
|     /* Recur on the children. */ | |
|     minNv = CountMinterms(dd, Nv, max, mintermTable, fp); | |
|     if (minNv == -1.0) return(-1.0); | |
|     minNnv = CountMinterms(dd, Nnv, max, mintermTable, fp); | |
|     if (minNnv == -1.0) return(-1.0); | |
|     min = minNv / 2.0 + minNnv / 2.0; | |
|     /* store  | |
|      */ | |
| 
 | |
|     dummy = ALLOC(double, 1); | |
|     if (dummy == NULL) return(-1.0); | |
|     *dummy = min; | |
|     if (st_insert(mintermTable, node, dummy) == ST_OUT_OF_MEM) { | |
| 	(void) fprintf(fp, "st table insert failed\n"); | |
|     } | |
|     return(min); | |
| 
 | |
| } /* end of CountMinterms */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Free factors structure | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static void | |
| ConjunctsFree( | |
|   DdManager * dd, | |
|   Conjuncts * factors) | |
| { | |
|     Cudd_RecursiveDeref(dd, factors->g); | |
|     Cudd_RecursiveDeref(dd, factors->h); | |
|     FREE(factors); | |
|     return; | |
| 
 | |
| } /* end of ConjunctsFree */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Check whether the given pair is in the tables. | |
|  | |
|   @details gTable and hTable are combined. | |
|   absence in both is indicated by 0, | |
|   presence in gTable is indicated by 1, | |
|   presence in hTable by 2 and | |
|   presence in both by 3. | |
|   The values returned by this function are PAIR_ST, | |
|   PAIR_CR, G_ST, G_CR, H_ST, H_CR, BOTH_G, BOTH_H, NONE. | |
|   PAIR_ST implies g in gTable and h in hTable | |
|   PAIR_CR implies g in hTable and h in gTable | |
|   G_ST implies g in gTable and h not in any table | |
|   G_CR implies g in hTable and h not in any table | |
|   H_ST implies h in hTable and g not in any table | |
|   H_CR implies h in gTable and g not in any table | |
|   BOTH_G implies both in gTable | |
|   BOTH_H implies both in hTable | |
|   NONE implies none in table;  | |
|  | |
|   @see CheckTablesCacheAndReturn CheckInTables | |
|  | |
| */ | |
| static int | |
| PairInTables( | |
|   DdNode * g, | |
|   DdNode * h, | |
|   st_table * ghTable) | |
| { | |
|     int valueG, valueH, gPresent, hPresent; | |
| 
 | |
|     valueG = valueH = gPresent = hPresent = 0; | |
|      | |
|     gPresent = st_lookup_int(ghTable, Cudd_Regular(g), &valueG); | |
|     hPresent = st_lookup_int(ghTable, Cudd_Regular(h), &valueH); | |
| 
 | |
|     if (!gPresent && !hPresent) return(NONE); | |
| 
 | |
|     if (!hPresent) { | |
| 	if (valueG & 1) return(G_ST); | |
| 	if (valueG & 2) return(G_CR); | |
|     } | |
|     if (!gPresent) { | |
| 	if (valueH & 1) return(H_CR); | |
| 	if (valueH & 2) return(H_ST); | |
|     } | |
|     /* both in tables */ | |
|     if ((valueG & 1) && (valueH & 2)) return(PAIR_ST); | |
|     if ((valueG & 2) && (valueH & 1)) return(PAIR_CR); | |
|      | |
|     if (valueG & 1) { | |
| 	return(BOTH_G); | |
|     } else { | |
| 	return(BOTH_H); | |
|     } | |
|      | |
| } /* end of PairInTables */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Check the tables for the existence of pair and return one | |
|   combination, cache the result. | |
|  | |
|   @details The assumption is that one of the conjuncts is already in | |
|   the tables. | |
|  | |
|   @sideeffect g and h referenced for the cache | |
|  | |
|   @see ZeroCase | |
|  | |
| */ | |
| static Conjuncts * | |
| CheckTablesCacheAndReturn( | |
|   DdManager * manager, | |
|   DdNode * node, | |
|   DdNode * g, | |
|   DdNode * h, | |
|   st_table * ghTable, | |
|   st_table * cacheTable) | |
| { | |
|     int pairValue; | |
|     int value; | |
|     Conjuncts *factors; | |
|      | |
|     value = 0; | |
|     /* check tables */ | |
|     pairValue = PairInTables(g, h, ghTable); | |
|     assert(pairValue != NONE); | |
|     /* if both dont exist in table, we know one exists(either g or h). | |
|      * Therefore store the other and proceed | |
|      */ | |
|     factors = ALLOC(Conjuncts, 1); | |
|     if (factors == NULL) return(NULL); | |
|     if ((pairValue == BOTH_H) || (pairValue == H_ST)) { | |
| 	if (g != DD_ONE(manager)) { | |
| 	    value = 0; | |
| 	    if (st_lookup_int(ghTable, Cudd_Regular(g), &value)) { | |
| 		value |= 1; | |
| 	    } else { | |
| 		value = 1; | |
| 	    } | |
| 	    if (st_insert(ghTable, Cudd_Regular(g), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = g; | |
| 	factors->h = h; | |
|     } else  if ((pairValue == BOTH_G) || (pairValue == G_ST)) { | |
| 	if (h != DD_ONE(manager)) { | |
| 	    value = 0; | |
| 	    if (st_lookup_int(ghTable, Cudd_Regular(h), &value)) { | |
| 		value |= 2; | |
| 	    } else { | |
| 		value = 2; | |
| 	    } | |
| 	    if (st_insert(ghTable, Cudd_Regular(h), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = g; | |
| 	factors->h = h; | |
|     } else if (pairValue == H_CR) { | |
| 	if (g != DD_ONE(manager)) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = h; | |
| 	factors->h = g; | |
|     } else if (pairValue == G_CR) { | |
| 	if (h != DD_ONE(manager)) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = h; | |
| 	factors->h = g; | |
|     } else if (pairValue == PAIR_CR) { | |
|     /* pair exists in table */ | |
| 	factors->g = h; | |
| 	factors->h = g; | |
|     } else if (pairValue == PAIR_ST) { | |
| 	factors->g = g; | |
| 	factors->h = h; | |
|     } | |
| 	     | |
|     /* cache the result for this node */ | |
|     if (st_insert(cacheTable, node, factors) == ST_OUT_OF_MEM) { | |
| 	FREE(factors); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     return(factors); | |
| 
 | |
| } /* end of CheckTablesCacheAndReturn */ | |
| 	 | |
| /** | |
|   @brief Check the tables for the existence of pair and return one | |
|   combination, store in cache. | |
|  | |
|   @details The pair that has more pointers to it is picked. An | |
|   approximation of the number of local pointers is made by taking the | |
|   reference count of the pairs sent. | |
|  | |
|   @see ZeroCase BuildConjuncts | |
|  | |
| */ | |
| static Conjuncts * | |
| PickOnePair( | |
|   DdManager * manager, | |
|   DdNode * node, | |
|   DdNode * g1, | |
|   DdNode * h1, | |
|   DdNode * g2, | |
|   DdNode * h2, | |
|   st_table * ghTable, | |
|   st_table * cacheTable) | |
| { | |
|     int value; | |
|     Conjuncts *factors; | |
|     int oneRef, twoRef; | |
|      | |
|     factors = ALLOC(Conjuncts, 1); | |
|     if (factors == NULL) return(NULL); | |
| 
 | |
|     /* count the number of pointers to pair 2 */ | |
|     if (h2 == DD_ONE(manager)) { | |
| 	twoRef = (Cudd_Regular(g2))->ref; | |
|     } else if (g2 == DD_ONE(manager)) { | |
| 	twoRef = (Cudd_Regular(h2))->ref; | |
|     } else { | |
| 	twoRef = ((Cudd_Regular(g2))->ref + (Cudd_Regular(h2))->ref)/2; | |
|     } | |
| 
 | |
|     /* count the number of pointers to pair 1 */ | |
|     if (h1 == DD_ONE(manager)) { | |
| 	oneRef  = (Cudd_Regular(g1))->ref; | |
|     } else if (g1 == DD_ONE(manager)) { | |
| 	oneRef  = (Cudd_Regular(h1))->ref; | |
|     } else { | |
| 	oneRef = ((Cudd_Regular(g1))->ref + (Cudd_Regular(h1))->ref)/2; | |
|     } | |
| 
 | |
|     /* pick the pair with higher reference count */ | |
|     if (oneRef >= twoRef) { | |
| 	factors->g = g1; | |
| 	factors->h = h1; | |
|     } else { | |
| 	factors->g = g2; | |
| 	factors->h = h2; | |
|     } | |
|      | |
|     /* | |
|      * Store computed factors in respective tables to encourage | |
|      * recombination. | |
|      */ | |
|     if (factors->g != DD_ONE(manager)) { | |
| 	/* insert g in htable */ | |
| 	value = 0; | |
| 	if (st_lookup_int(ghTable, Cudd_Regular(factors->g), &value)) { | |
| 	    if (value == 2) { | |
| 		value |= 1; | |
| 		if (st_insert(ghTable, Cudd_Regular(factors->g), | |
| 			      (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		    FREE(factors); | |
| 		    return(NULL); | |
| 		} | |
| 	    } | |
| 	} else { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(factors->g), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
| 
 | |
|     if (factors->h != DD_ONE(manager)) { | |
| 	/* insert h in htable */ | |
| 	value = 0; | |
| 	if (st_lookup_int(ghTable, Cudd_Regular(factors->h), &value)) { | |
| 	    if (value == 1) { | |
| 		value |= 2; | |
| 		if (st_insert(ghTable, Cudd_Regular(factors->h), | |
| 			      (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		    FREE(factors); | |
| 		    return(NULL); | |
| 		} | |
| 	    }	     | |
| 	} else { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(factors->h), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
|      | |
|     /* Store factors in cache table for later use. */ | |
|     if (st_insert(cacheTable, node, factors) == | |
| 	    ST_OUT_OF_MEM) { | |
| 	FREE(factors); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     return(factors); | |
| 
 | |
| } /* end of PickOnePair */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Check if the two pairs exist in the table. | |
|  | |
|   @details If any of the conjuncts do exist, store in the cache and | |
|   return the corresponding pair. | |
|  | |
|   @see ZeroCase BuildConjuncts | |
|  | |
| */ | |
| static Conjuncts * | |
| CheckInTables( | |
|   DdManager * manager, | |
|   DdNode * node, | |
|   DdNode * g1, | |
|   DdNode * h1, | |
|   DdNode * g2, | |
|   DdNode * h2, | |
|   st_table * ghTable, | |
|   st_table * cacheTable, | |
|   int * outOfMem) | |
| { | |
|     int pairValue1,  pairValue2; | |
|     Conjuncts *factors; | |
|     int value; | |
|      | |
|     *outOfMem = 0; | |
| 
 | |
|     /* check existence of pair in table */ | |
|     pairValue1 = PairInTables(g1, h1, ghTable); | |
|     pairValue2 = PairInTables(g2, h2, ghTable); | |
| 
 | |
|     /* if none of the 4 exist in the gh tables, return NULL */ | |
|     if ((pairValue1 == NONE) && (pairValue2 == NONE)) { | |
| 	return NULL; | |
|     } | |
|      | |
|     factors = ALLOC(Conjuncts, 1); | |
|     if (factors == NULL) { | |
| 	*outOfMem = 1; | |
| 	return NULL; | |
|     } | |
| 
 | |
|     /* pairs that already exist in the table get preference. */ | |
|     if (pairValue1 == PAIR_ST) { | |
| 	factors->g = g1; | |
| 	factors->h = h1; | |
|     } else if (pairValue2 == PAIR_ST) { | |
| 	factors->g = g2; | |
| 	factors->h = h2; | |
|     } else if (pairValue1 == PAIR_CR) { | |
| 	factors->g = h1; | |
| 	factors->h = g1; | |
|     } else if (pairValue2 == PAIR_CR) { | |
| 	factors->g = h2; | |
| 	factors->h = g2; | |
|     } else if (pairValue1 == G_ST) { | |
| 	/* g exists in the table, h is not found in either table */ | |
| 	factors->g = g1; | |
| 	factors->h = h1; | |
| 	if (h1 != DD_ONE(manager)) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h1), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue1 == BOTH_G) { | |
| 	/* g and h are  found in the g table */ | |
| 	factors->g = g1; | |
| 	factors->h = h1; | |
| 	if (h1 != DD_ONE(manager)) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h1), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue1 == H_ST) { | |
| 	/* h exists in the table, g is not found in either table */ | |
| 	factors->g = g1; | |
| 	factors->h = h1; | |
| 	if (g1 != DD_ONE(manager)) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g1), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue1 == BOTH_H) { | |
| 	/* g and h are  found in the h table */ | |
| 	factors->g = g1; | |
| 	factors->h = h1; | |
| 	if (g1 != DD_ONE(manager)) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g1), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue2 == G_ST) { | |
| 	/* g exists in the table, h is not found in either table */ | |
| 	factors->g = g2; | |
| 	factors->h = h2; | |
| 	if (h2 != DD_ONE(manager)) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h2), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if  (pairValue2 == BOTH_G) { | |
| 	/* g and h are  found in the g table */ | |
| 	factors->g = g2; | |
| 	factors->h = h2; | |
| 	if (h2 != DD_ONE(manager)) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h2), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue2 == H_ST) {  | |
| 	/* h exists in the table, g is not found in either table */ | |
| 	factors->g = g2; | |
| 	factors->h = h2; | |
| 	if (g2 != DD_ONE(manager)) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g2), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue2 == BOTH_H) { | |
| 	/* g and h are  found in the h table */ | |
| 	factors->g = g2; | |
| 	factors->h = h2; | |
| 	if (g2 != DD_ONE(manager)) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g2), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue1 == G_CR) { | |
| 	/* g found in h table and h in none */ | |
| 	factors->g = h1; | |
| 	factors->h = g1; | |
| 	if (h1 != DD_ONE(manager)) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h1), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue1 == H_CR) { | |
| 	/* h found in g table and g in none */ | |
| 	factors->g = h1; | |
| 	factors->h = g1; | |
| 	if (g1 != DD_ONE(manager)) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g1), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue2 == G_CR) { | |
| 	/* g found in h table and h in none */ | |
| 	factors->g = h2; | |
| 	factors->h = g2; | |
| 	if (h2 != DD_ONE(manager)) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(h2), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } else if (pairValue2 == H_CR) { | |
| 	/* h found in g table and g in none */ | |
| 	factors->g = h2; | |
| 	factors->h = g2; | |
| 	if (g2 != DD_ONE(manager)) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(g2), | |
| 			  (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
|      | |
|     /* Store factors in cache table for later use. */ | |
|     if (st_insert(cacheTable, node, factors) == | |
| 	    ST_OUT_OF_MEM) { | |
| 	*outOfMem = 1; | |
| 	FREE(factors); | |
| 	return(NULL); | |
|     } | |
|     return factors; | |
| } /* end of CheckInTables */ | |
| 
 | |
| 
 | |
| 
 | |
| /** | |
|   @brief If one child is zero, do explicitly what Restrict does or better | |
|  | |
|   @details First separate a variable and its child in the base | |
|   case. In case of a cube times a function, separate the cube and | |
|   function. As a last resort, look in tables. | |
|  | |
|   @sideeffect Frees the BDDs in factorsNv. factorsNv itself is not freed | |
|   because it is freed above. | |
|  | |
|   @see BuildConjuncts | |
|  | |
| */ | |
| static Conjuncts * | |
| ZeroCase( | |
|   DdManager * dd, | |
|   DdNode * node, | |
|   Conjuncts * factorsNv, | |
|   st_table * ghTable, | |
|   st_table * cacheTable, | |
|   int switched) | |
| { | |
|     int topid; | |
|     DdNode *g, *h, *g1, *g2, *h1, *h2, *x, *N, *G, *H, *Gv, *Gnv; | |
|     DdNode *Hv, *Hnv; | |
|     int value; | |
|     int outOfMem; | |
|     Conjuncts *factors; | |
|      | |
|     /* get var at this node */ | |
|     N = Cudd_Regular(node); | |
|     topid = N->index; | |
|     x = dd->vars[topid]; | |
|     x = (switched) ? Cudd_Not(x): x; | |
|     cuddRef(x); | |
| 
 | |
|     /* Seprate variable and child */ | |
|     if (factorsNv->g == DD_ONE(dd)) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	factors = ALLOC(Conjuncts, 1); | |
| 	if (factors == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	    Cudd_RecursiveDeref(dd, x); | |
| 	    return(NULL); | |
| 	} | |
| 	factors->g = x; | |
| 	factors->h = factorsNv->h; | |
| 	/* cache the result*/ | |
| 	if (st_insert(cacheTable, node, factors) == ST_OUT_OF_MEM) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    Cudd_RecursiveDeref(dd, factorsNv->h);  | |
| 	    Cudd_RecursiveDeref(dd, x); | |
| 	    FREE(factors); | |
| 	    return NULL; | |
| 	} | |
| 	 | |
| 	/* store  x in g table, the other node is already in the table */ | |
| 	if (st_lookup_int(ghTable, Cudd_Regular(x), &value)) { | |
| 	    value |= 1; | |
| 	} else { | |
| 	    value = 1; | |
| 	} | |
| 	if (st_insert(ghTable, Cudd_Regular(x), (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return NULL; | |
| 	} | |
| 	return(factors); | |
|     } | |
|      | |
|     /* Seprate variable and child */ | |
|     if (factorsNv->h == DD_ONE(dd)) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	factors = ALLOC(Conjuncts, 1); | |
| 	if (factors == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	    Cudd_RecursiveDeref(dd, x); | |
| 	    return(NULL); | |
| 	} | |
| 	factors->g = factorsNv->g; | |
| 	factors->h = x; | |
| 	/* cache the result. */ | |
|  	if (st_insert(cacheTable, node, factors) == ST_OUT_OF_MEM) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	    Cudd_RecursiveDeref(dd, x); | |
| 	    FREE(factors); | |
| 	    return(NULL); | |
| 	} | |
| 	/* store x in h table,  the other node is already in the table */ | |
| 	if (st_lookup_int(ghTable, Cudd_Regular(x), &value)) { | |
| 	    value |= 2; | |
| 	} else { | |
| 	    value = 2; | |
| 	} | |
| 	if (st_insert(ghTable, Cudd_Regular(x), (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return NULL; | |
| 	} | |
| 	return(factors); | |
|     } | |
| 
 | |
|     G = Cudd_Regular(factorsNv->g); | |
|     Gv = cuddT(G); | |
|     Gnv = cuddE(G); | |
|     Gv = Cudd_NotCond(Gv, Cudd_IsComplement(node)); | |
|     Gnv = Cudd_NotCond(Gnv, Cudd_IsComplement(node)); | |
|     /* if the child below is a variable */ | |
|     if ((Gv == Cudd_Not(DD_ONE(dd))) || (Gnv == Cudd_Not(DD_ONE(dd)))) { | |
| 	h = factorsNv->h; | |
| 	g = cuddBddAndRecur(dd, x, factorsNv->g); | |
| 	if (g != NULL) 	cuddRef(g); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g);  | |
| 	Cudd_RecursiveDeref(dd, x); | |
| 	if (g == NULL) { | |
| 	    Cudd_RecursiveDeref(dd, factorsNv->h);  | |
| 	    return NULL; | |
| 	} | |
| 	/* CheckTablesCacheAndReturn responsible for allocating | |
| 	 * factors structure., g,h referenced for cache store  the | |
| 	 */ | |
| 	factors = CheckTablesCacheAndReturn(dd, | |
| 					    node, | |
| 					    g, | |
| 					    h, | |
| 					    ghTable, | |
| 					    cacheTable); | |
| 	if (factors == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    Cudd_RecursiveDeref(dd, g); | |
| 	    Cudd_RecursiveDeref(dd, h); | |
| 	} | |
| 	return(factors);  | |
|     } | |
| 
 | |
|     H = Cudd_Regular(factorsNv->h); | |
|     Hv = cuddT(H); | |
|     Hnv = cuddE(H); | |
|     Hv = Cudd_NotCond(Hv, Cudd_IsComplement(node)); | |
|     Hnv = Cudd_NotCond(Hnv, Cudd_IsComplement(node)); | |
|     /* if the child below is a variable */ | |
|     if ((Hv == Cudd_Not(DD_ONE(dd))) || (Hnv == Cudd_Not(DD_ONE(dd)))) { | |
| 	g = factorsNv->g; | |
| 	h = cuddBddAndRecur(dd, x, factorsNv->h); | |
| 	if (h!= NULL) cuddRef(h); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	Cudd_RecursiveDeref(dd, x); | |
| 	if (h == NULL) { | |
| 	    Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	    return NULL; | |
| 	} | |
| 	/* CheckTablesCacheAndReturn responsible for allocating | |
| 	 * factors structure.g,h referenced for table store  | |
| 	 */ | |
| 	factors = CheckTablesCacheAndReturn(dd, | |
| 					    node, | |
| 					    g, | |
| 					    h, | |
| 					    ghTable, | |
| 					    cacheTable); | |
| 	if (factors == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    Cudd_RecursiveDeref(dd, g); | |
| 	    Cudd_RecursiveDeref(dd, h); | |
| 	} | |
| 	return(factors);  | |
|     } | |
| 
 | |
|     /* build g1 = x*g; h1 = h */ | |
|     /* build g2 = g; h2 = x*h */ | |
|     Cudd_RecursiveDeref(dd, x); | |
|     h1 = factorsNv->h; | |
|     g1 = cuddBddAndRecur(dd, x, factorsNv->g); | |
|     if (g1 != NULL) cuddRef(g1); | |
|     if (g1 == NULL) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g);  | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	return NULL; | |
|     } | |
|      | |
|     g2 = factorsNv->g; | |
|     h2 = cuddBddAndRecur(dd, x, factorsNv->h); | |
|     if (h2 != NULL) cuddRef(h2); | |
|     if (h2 == NULL) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	return NULL; | |
|     } | |
| 
 | |
|     /* check whether any pair is in tables */ | |
|     factors = CheckInTables(dd, node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem); | |
|     if (outOfMem) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	Cudd_RecursiveDeref(dd, h1); | |
| 	Cudd_RecursiveDeref(dd, g2); | |
| 	Cudd_RecursiveDeref(dd, h2); | |
| 	return NULL; | |
|     } | |
|     if (factors != NULL) { | |
| 	if ((factors->g == g1) || (factors->g == h1)) { | |
| 	    Cudd_RecursiveDeref(dd, g2); | |
| 	    Cudd_RecursiveDeref(dd, h2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd, g1); | |
| 	    Cudd_RecursiveDeref(dd, h1); | |
| 	} | |
| 	return factors; | |
|     } | |
| 
 | |
|     /* check for each pair in tables and choose one */ | |
|     factors = PickOnePair(dd, node,g1, h1, g2, h2, ghTable, cacheTable); | |
|     if (factors == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	Cudd_RecursiveDeref(dd, h1); | |
| 	Cudd_RecursiveDeref(dd, g2); | |
| 	Cudd_RecursiveDeref(dd, h2); | |
|     } else { | |
| 	/* now free what was created and not used */ | |
| 	if ((factors->g == g1) || (factors->g == h1)) { | |
| 	    Cudd_RecursiveDeref(dd, g2); | |
| 	    Cudd_RecursiveDeref(dd, h2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd, g1); | |
| 	    Cudd_RecursiveDeref(dd, h1); | |
| 	} | |
|     } | |
| 	 | |
|     return(factors); | |
| } /* end of ZeroCase */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Builds the conjuncts recursively, bottom up. | |
|  | |
|   @details Constants are returned as (f, f). The cache is checked for | |
|   previously computed result. The decomposition points are determined | |
|   by the local reference count of this node and the longest distance | |
|   from the constant. At the decomposition point, the factors returned | |
|   are (f, 1). Recur on the two children. The order is determined by | |
|   the heavier branch. Combine the factors of the two children and pick | |
|   the one that already occurs in the gh table. Occurence in g is | |
|   indicated by value 1, occurence in h by 2, occurence in both by 3. | |
|  | |
|   @see cuddConjunctsAux | |
|  | |
| */ | |
| static Conjuncts * | |
| BuildConjuncts( | |
|   DdManager * dd, | |
|   DdNode * node, | |
|   st_table * distanceTable, | |
|   st_table * cacheTable, | |
|   int approxDistance, | |
|   int maxLocalRef, | |
|   st_table * ghTable, | |
|   st_table * mintermTable, | |
|   int32_t *lastTimeG) | |
| { | |
|     int topid, distance; | |
|     Conjuncts *factorsNv = NULL, *factorsNnv = NULL, *factors; | |
|     void *dummy; | |
|     DdNode *N, *Nv, *Nnv, *temp, *g1, *g2, *h1, *h2, *topv; | |
|     double minNv = 0.0, minNnv = 0.0; | |
|     double *doubleDummy; | |
|     int switched =0; | |
|     int outOfMem; | |
|     int freeNv = 0, freeNnv = 0, freeTemp; | |
|     NodeStat *nodeStat; | |
|     int value; | |
|     DdNode * const one = DD_ONE(dd); | |
|     DdNode * const zero = Cudd_Not(one); | |
| 
 | |
|     /* if f is constant, return (f,f) */ | |
|     if (Cudd_IsConstantInt(node)) { | |
| 	factors = ALLOC(Conjuncts, 1); | |
| 	if (factors == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(NULL); | |
| 	} | |
| 	factors->g = node; | |
| 	factors->h = node; | |
| 	return(FactorsComplement(factors)); | |
|     } | |
| 
 | |
|     /* If result (a pair of conjuncts) in cache, return the factors. */ | |
|     if (st_lookup(cacheTable, node, &dummy)) { | |
|         factors = (Conjuncts *) dummy; | |
| 	return(factors); | |
|     } | |
| 
 | |
|     /* check distance and local reference count of this node */ | |
|     N = Cudd_Regular(node); | |
|     if (!st_lookup(distanceTable, N, (void **) &nodeStat)) { | |
| 	(void) fprintf(dd->err, "Not in table, Something wrong\n"); | |
| 	dd->errorCode = CUDD_INTERNAL_ERROR; | |
| 	return(NULL); | |
|     } | |
|     distance = nodeStat->distance; | |
| 
 | |
|     /* at or below decomposition point, return (f, 1) */ | |
|     if (((nodeStat->localRef > maxLocalRef*2/3) && | |
| 	 (distance < approxDistance*2/3)) || | |
| 	    (distance <= approxDistance/4)) { | |
| 	factors = ALLOC(Conjuncts, 1); | |
| 	if (factors == NULL) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(NULL); | |
| 	} | |
| 	/* alternate assigning (f,1) */ | |
| 	value = 0; | |
| 	if (st_lookup_int(ghTable, Cudd_Regular(node), &value)) { | |
| 	    if (value == 3) { | |
| 		if (!*lastTimeG) { | |
| 		    factors->g = node; | |
| 		    factors->h = one; | |
| 		    *lastTimeG = 1; | |
| 		} else { | |
| 		    factors->g = one; | |
| 		    factors->h = node; | |
| 		    *lastTimeG = 0;  | |
| 		} | |
| 	    } else if (value == 1) { | |
| 		factors->g = node; | |
| 		factors->h = one; | |
| 	    } else { | |
| 		factors->g = one; | |
| 		factors->h = node; | |
| 	    } | |
| 	} else if (!*lastTimeG) { | |
| 	    factors->g = node; | |
| 	    factors->h = one; | |
| 	    *lastTimeG = 1; | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, Cudd_Regular(node), (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		FREE(factors); | |
| 		return NULL; | |
| 	    } | |
| 	} else { | |
| 	    factors->g = one; | |
| 	    factors->h = node; | |
| 	    *lastTimeG = 0; | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, Cudd_Regular(node), (void *)(ptruint)value) == ST_OUT_OF_MEM) { | |
| 		dd->errorCode = CUDD_MEMORY_OUT; | |
| 		FREE(factors); | |
| 		return NULL; | |
| 	    } | |
| 	} | |
| 	return(FactorsComplement(factors)); | |
|     } | |
| 
 | |
|     /* get the children and recur */ | |
|     Nv = cuddT(N); | |
|     Nnv = cuddE(N); | |
|     Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node)); | |
|     Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node)); | |
| 
 | |
|     /* Choose which subproblem to solve first based on the number of | |
|      * minterms. We go first where there are more minterms. | |
|      */ | |
|     if (!Cudd_IsConstantInt(Nv)) { | |
| 	if (!st_lookup(mintermTable, Nv, (void **) &doubleDummy)) { | |
| 	    (void) fprintf(dd->err, "Not in table: Something wrong\n"); | |
| 	    dd->errorCode = CUDD_INTERNAL_ERROR; | |
| 	    return(NULL); | |
| 	} | |
| 	minNv = *doubleDummy; | |
|     } | |
| 
 | |
|     if (!Cudd_IsConstantInt(Nnv)) { | |
| 	if (!st_lookup(mintermTable, Nnv, (void **) &doubleDummy)) { | |
| 	    (void) fprintf(dd->err, "Not in table: Something wrong\n"); | |
| 	    dd->errorCode = CUDD_INTERNAL_ERROR; | |
| 	    return(NULL); | |
| 	} | |
| 	minNnv = *doubleDummy; | |
|     } | |
| 
 | |
|     if (minNv < minNnv) { | |
| 	temp = Nv; | |
| 	Nv = Nnv; | |
| 	Nnv = temp; | |
| 	switched = 1; | |
|     } | |
| 
 | |
|     /* build gt, ht recursively */ | |
|     if (Nv != zero) { | |
| 	factorsNv = BuildConjuncts(dd, Nv, distanceTable, | |
| 				   cacheTable, approxDistance, maxLocalRef,  | |
| 				   ghTable, mintermTable, lastTimeG); | |
| 	if (factorsNv == NULL) return(NULL); | |
| 	freeNv = FactorsNotStored(factorsNv); | |
| 	factorsNv = (freeNv) ? FactorsUncomplement(factorsNv) : factorsNv; | |
| 	cuddRef(factorsNv->g); | |
| 	cuddRef(factorsNv->h); | |
| 
 | |
| 	/* Deal with the zero case */ | |
| 	if (Nnv == zero) { | |
| 	    /* is responsible for freeing factorsNv */ | |
| 	    factors = ZeroCase(dd, node, factorsNv, ghTable, | |
| 			       cacheTable, switched); | |
| 	    if (freeNv) FREE(factorsNv); | |
| 	    return(factors); | |
| 	} | |
|     } | |
| 
 | |
|     /* build ge, he recursively */ | |
|     if (Nnv != zero) { | |
| 	factorsNnv = BuildConjuncts(dd, Nnv, distanceTable, | |
| 				    cacheTable, approxDistance, maxLocalRef, | |
| 				    ghTable, mintermTable, lastTimeG); | |
| 	if (factorsNnv == NULL) { | |
|             if (factorsNv != NULL) { | |
|                 Cudd_RecursiveDeref(dd, factorsNv->g); | |
|                 Cudd_RecursiveDeref(dd, factorsNv->h); | |
|                 if (freeNv) FREE(factorsNv); | |
|             } | |
| 	    return(NULL); | |
| 	} | |
| 	freeNnv = FactorsNotStored(factorsNnv); | |
| 	factorsNnv = (freeNnv) ? FactorsUncomplement(factorsNnv) : factorsNnv; | |
| 	cuddRef(factorsNnv->g); | |
| 	cuddRef(factorsNnv->h); | |
| 	 | |
| 	/* Deal with the zero case */ | |
| 	if (Nv == zero) { | |
| 	    /* is responsible for freeing factorsNv */ | |
| 	    factors = ZeroCase(dd, node, factorsNnv, ghTable, | |
| 			       cacheTable, switched); | |
| 	    if (freeNnv) FREE(factorsNnv); | |
| 	    return(factors); | |
| 	} | |
|     } | |
| 
 | |
|     /* construct the 2 pairs */ | |
|     /* g1 = x*gt + x'*ge; h1 = x*ht + x'*he; */ | |
|     /* g2 = x*gt + x'*he; h2 = x*ht + x'*ge */ | |
|     if (switched) { | |
| 	factors = factorsNnv; | |
| 	factorsNnv = factorsNv; | |
| 	factorsNv = factors; | |
| 	freeTemp = freeNv; | |
| 	freeNv = freeNnv; | |
| 	freeNnv = freeTemp; | |
|     } | |
| 
 | |
|     /* Build the factors for this node. */ | |
|     topid = N->index; | |
|     topv = dd->vars[topid]; | |
| 
 | |
|     g1 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->g); | |
|     if (g1 == NULL) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->h); | |
| 	if (freeNv) FREE(factorsNv); | |
| 	if (freeNnv) FREE(factorsNnv); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     cuddRef(g1); | |
| 
 | |
|     h1 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->h); | |
|     if (h1 == NULL) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->h); | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	if (freeNv) FREE(factorsNv); | |
| 	if (freeNnv) FREE(factorsNnv); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     cuddRef(h1); | |
| 
 | |
|     g2 = cuddBddIteRecur(dd, topv, factorsNv->g, factorsNnv->h); | |
|     if (g2 == NULL) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->h); | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	Cudd_RecursiveDeref(dd, h1); | |
| 	if (freeNv) FREE(factorsNv); | |
| 	if (freeNnv) FREE(factorsNnv); | |
| 	return(NULL); | |
|     } | |
|     cuddRef(g2); | |
|     Cudd_RecursiveDeref(dd, factorsNv->g); | |
|     Cudd_RecursiveDeref(dd, factorsNnv->h); | |
| 
 | |
|     h2 = cuddBddIteRecur(dd, topv, factorsNv->h, factorsNnv->g); | |
|     if (h2 == NULL) { | |
| 	Cudd_RecursiveDeref(dd, factorsNv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNv->h); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->g); | |
| 	Cudd_RecursiveDeref(dd, factorsNnv->h); | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	Cudd_RecursiveDeref(dd, h1); | |
| 	Cudd_RecursiveDeref(dd, g2); | |
| 	if (freeNv) FREE(factorsNv); | |
| 	if (freeNnv) FREE(factorsNnv); | |
| 	return(NULL); | |
|     } | |
|     cuddRef(h2); | |
|     Cudd_RecursiveDeref(dd, factorsNv->h); | |
|     Cudd_RecursiveDeref(dd, factorsNnv->g); | |
|     if (freeNv) FREE(factorsNv); | |
|     if (freeNnv) FREE(factorsNnv); | |
| 
 | |
|     /* check for each pair in tables and choose one */ | |
|     factors = CheckInTables(dd, node, g1, h1, g2, h2, ghTable, cacheTable, &outOfMem); | |
|     if (outOfMem) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	Cudd_RecursiveDeref(dd, h1); | |
| 	Cudd_RecursiveDeref(dd, g2); | |
| 	Cudd_RecursiveDeref(dd, h2); | |
| 	return(NULL); | |
|     } | |
|     if (factors != NULL) { | |
| 	if ((factors->g == g1) || (factors->g == h1)) { | |
| 	    Cudd_RecursiveDeref(dd, g2); | |
| 	    Cudd_RecursiveDeref(dd, h2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd, g1); | |
| 	    Cudd_RecursiveDeref(dd, h1); | |
| 	} | |
| 	return(factors); | |
|     } | |
| 
 | |
|     /* if not in tables, pick one pair */ | |
|     factors = PickOnePair(dd, node, g1, h1, g2, h2, ghTable, cacheTable); | |
|     if (factors == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	Cudd_RecursiveDeref(dd, g1); | |
| 	Cudd_RecursiveDeref(dd, h1); | |
| 	Cudd_RecursiveDeref(dd, g2); | |
| 	Cudd_RecursiveDeref(dd, h2); | |
|     } else { | |
| 	/* now free what was created and not used */ | |
| 	if ((factors->g == g1) || (factors->g == h1)) { | |
| 	    Cudd_RecursiveDeref(dd, g2); | |
| 	    Cudd_RecursiveDeref(dd, h2); | |
| 	} else { | |
| 	    Cudd_RecursiveDeref(dd, g1); | |
| 	    Cudd_RecursiveDeref(dd, h1); | |
| 	} | |
|     } | |
| 
 | |
|     return(factors); | |
| 
 | |
| } /* end of BuildConjuncts */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Computes two conjunctive factors of f and places them in *c1 and *c2. | |
|  | |
|   @details Sets up the required data - table of distances from the | |
|   constant and local reference count. Also minterm table. | |
|  | |
| */ | |
| static int | |
| cuddConjunctsAux( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   DdNode ** c1, | |
|   DdNode ** c2) | |
| { | |
|     st_table *distanceTable = NULL; | |
|     st_table *cacheTable = NULL; | |
|     st_table *mintermTable = NULL; | |
|     st_table *ghTable = NULL; | |
|     st_generator *stGen; | |
|     char *key, *value; | |
|     Conjuncts *factors; | |
|     int distance, approxDistance; | |
|     double max, minterms; | |
|     int freeFactors; | |
|     NodeStat *nodeStat; | |
|     int maxLocalRef; | |
|     int32_t lastTimeG; | |
| 
 | |
|     /* initialize */ | |
|     *c1 = NULL; | |
|     *c2 = NULL; | |
| 
 | |
|     /* initialize distances table */ | |
|     distanceTable = st_init_table(st_ptrcmp,st_ptrhash); | |
|     if (distanceTable == NULL) goto outOfMem; | |
|      | |
|     /* make the entry for the constant */ | |
|     nodeStat = ALLOC(NodeStat, 1); | |
|     if (nodeStat == NULL) goto outOfMem; | |
|     nodeStat->distance = 0; | |
|     nodeStat->localRef = 1; | |
|     if (st_insert(distanceTable, DD_ONE(dd), nodeStat) == ST_OUT_OF_MEM) { | |
| 	goto outOfMem; | |
|     } | |
| 
 | |
|     /* Count node distances from constant. */ | |
|     nodeStat = CreateBotDist(f, distanceTable); | |
|     if (nodeStat == NULL) goto outOfMem; | |
| 
 | |
|     /* set the distance for the decomposition points */ | |
|     approxDistance = (DEPTH < nodeStat->distance) ? nodeStat->distance : DEPTH; | |
|     distance = nodeStat->distance; | |
| 
 | |
|     if (distance < approxDistance) { | |
| 	/* Too small to bother. */ | |
| 	*c1 = f; | |
| 	*c2 = DD_ONE(dd); | |
| 	cuddRef(*c1); cuddRef(*c2); | |
| 	stGen = st_init_gen(distanceTable); | |
| 	if (stGen == NULL) goto outOfMem; | |
| 	while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	    FREE(value); | |
| 	} | |
| 	st_free_gen(stGen); stGen = NULL; | |
| 	st_free_table(distanceTable); | |
| 	return(1); | |
|     } | |
| 
 | |
|     /* record the maximum local reference count */ | |
|     maxLocalRef = 0; | |
|     stGen = st_init_gen(distanceTable); | |
|     if (stGen == NULL) goto outOfMem; | |
|     while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	nodeStat = (NodeStat *)value; | |
| 	maxLocalRef = (nodeStat->localRef > maxLocalRef) ? | |
| 	    nodeStat->localRef : maxLocalRef; | |
|     } | |
|     st_free_gen(stGen); stGen = NULL; | |
| 
 | |
| 
 | |
|     /* Count minterms for each node. */ | |
|     max = pow(2.0, (double)Cudd_SupportSize(dd,f)); /* potential overflow */ | |
|     mintermTable = st_init_table(st_ptrcmp,st_ptrhash); | |
|     if (mintermTable == NULL) goto outOfMem; | |
|     minterms = CountMinterms(dd, f, max, mintermTable, dd->err); | |
|     if (minterms == -1.0) goto outOfMem; | |
|      | |
|     lastTimeG = Cudd_Random(dd) & 1; | |
|     cacheTable = st_init_table(st_ptrcmp, st_ptrhash); | |
|     if (cacheTable == NULL) goto outOfMem; | |
|     ghTable = st_init_table(st_ptrcmp, st_ptrhash); | |
|     if (ghTable == NULL) goto outOfMem; | |
| 
 | |
|     /* Build conjuncts. */ | |
|     factors = BuildConjuncts(dd, f, distanceTable, cacheTable, | |
| 			     approxDistance, maxLocalRef, ghTable, | |
|                              mintermTable, &lastTimeG); | |
|     if (factors == NULL) goto outOfMem; | |
| 
 | |
|     /* free up tables */ | |
|     stGen = st_init_gen(distanceTable); | |
|     if (stGen == NULL) goto outOfMem; | |
|     while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	FREE(value); | |
|     } | |
|     st_free_gen(stGen); stGen = NULL; | |
|     st_free_table(distanceTable); distanceTable = NULL; | |
|     st_free_table(ghTable); ghTable = NULL; | |
|      | |
|     stGen = st_init_gen(mintermTable); | |
|     if (stGen == NULL) goto outOfMem; | |
|     while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	FREE(value); | |
|     } | |
|     st_free_gen(stGen); stGen = NULL; | |
|     st_free_table(mintermTable); mintermTable = NULL; | |
| 
 | |
|     freeFactors = FactorsNotStored(factors); | |
|     factors = (freeFactors) ? FactorsUncomplement(factors) : factors; | |
|     if (factors != NULL) { | |
| 	*c1 = factors->g; | |
| 	*c2 = factors->h; | |
| 	cuddRef(*c1); | |
| 	cuddRef(*c2); | |
| 	if (freeFactors) FREE(factors); | |
| 	 | |
| #if 0     | |
| 	if ((*c1 == f) && (!Cudd_IsConstantInt(f))) { | |
| 	    assert(*c2 == DD_ONE(manager)); | |
| 	} | |
| 	if ((*c2 == f) && (!Cudd_IsConstantInt(f))) { | |
| 	    assert(*c1 == DD_ONE(manager)); | |
| 	} | |
| 	 | |
| 	if ((*c1 != DD_ONE(manager)) && (!Cudd_IsConstantInt(f))) { | |
| 	    assert(!Cudd_bddLeq(dd, *c2, *c1)); | |
| 	} | |
| 	if ((*c2 != DD_ONE(manager)) && (!Cudd_IsConstantInt(f))) { | |
| 	    assert(!Cudd_bddLeq(dd, *c1, *c2)); | |
| 	} | |
| #endif | |
|     } | |
| 
 | |
|     stGen = st_init_gen(cacheTable); | |
|     if (stGen == NULL) goto outOfMem; | |
|     while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	ConjunctsFree(dd, (Conjuncts *)value); | |
|     } | |
|     st_free_gen(stGen); stGen = NULL; | |
| 
 | |
|     st_free_table(cacheTable); cacheTable = NULL; | |
| 
 | |
|     return(1); | |
| 
 | |
| outOfMem: | |
|     if (distanceTable != NULL) { | |
| 	stGen = st_init_gen(distanceTable); | |
| 	if (stGen == NULL) goto outOfMem; | |
| 	while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	    FREE(value); | |
| 	} | |
| 	st_free_gen(stGen); stGen = NULL; | |
| 	st_free_table(distanceTable); distanceTable = NULL; | |
|     } | |
|     if (mintermTable != NULL) { | |
| 	stGen = st_init_gen(mintermTable); | |
| 	if (stGen == NULL) goto outOfMem; | |
| 	while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	    FREE(value); | |
| 	} | |
| 	st_free_gen(stGen); stGen = NULL; | |
| 	st_free_table(mintermTable); mintermTable = NULL; | |
|     } | |
|     if (ghTable != NULL) st_free_table(ghTable); | |
|     if (cacheTable != NULL) { | |
| 	stGen = st_init_gen(cacheTable); | |
| 	if (stGen == NULL) goto outOfMem; | |
| 	while(st_gen(stGen, (void **)&key, (void **)&value)) { | |
| 	    ConjunctsFree(dd, (Conjuncts *)value); | |
| 	} | |
| 	st_free_gen(stGen); stGen = NULL; | |
| 	st_free_table(cacheTable); cacheTable = NULL; | |
|     } | |
|     dd->errorCode = CUDD_MEMORY_OUT; | |
|     return(0); | |
| 
 | |
| } /* end of cuddConjunctsAux */
 |