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.
		
		
		
		
		
			
		
			
				
					
					
						
							2177 lines
						
					
					
						
							62 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							2177 lines
						
					
					
						
							62 KiB
						
					
					
				| /**CFile*********************************************************************** | |
|  | |
|   FileName    [cuddDecomp.c] | |
|  | |
|   PackageName [cudd] | |
|  | |
|   Synopsis    [Functions for BDD decomposition.] | |
|  | |
|   Description [External procedures included in this file: | |
| 		<ul> | |
| 		<li> Cudd_bddApproxConjDecomp() | |
| 		<li> Cudd_bddApproxDisjDecomp() | |
| 		<li> Cudd_bddIterConjDecomp() | |
| 		<li> Cudd_bddIterDisjDecomp() | |
| 		<li> Cudd_bddGenConjDecomp() | |
| 		<li> Cudd_bddGenDisjDecomp() | |
| 		<li> Cudd_bddVarConjDecomp() | |
| 		<li> Cudd_bddVarDisjDecomp() | |
| 		</ul> | |
| 	Static procedures included in this module: | |
| 		<ul> | |
| 		<li> cuddConjunctsAux() | |
| 		<li> CreateBotDist() | |
| 		<li> BuildConjuncts() | |
| 		<li> ConjunctsFree() | |
| 		</ul>] | |
|  | |
|   Author      [Kavita Ravi, Fabio Somenzi] | |
|  | |
|   Copyright   [Copyright (c) 1995-2012, Regents of the University of Colorado | |
|  | |
|   All rights reserved. | |
|  | |
|   Redistribution and use in source and binary forms, with or without | |
|   modification, are permitted provided that the following conditions | |
|   are met: | |
|  | |
|   Redistributions of source code must retain the above copyright | |
|   notice, this list of conditions and the following disclaimer. | |
|  | |
|   Redistributions in binary form must reproduce the above copyright | |
|   notice, this list of conditions and the following disclaimer in the | |
|   documentation and/or other materials provided with the distribution. | |
|  | |
|   Neither the name of the University of Colorado nor the names of its | |
|   contributors may be used to endorse or promote products derived from | |
|   this software without specific prior written permission. | |
|  | |
|   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
|   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
|   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
|   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
|   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
|   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
|   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
|   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
|   POSSIBILITY OF SUCH DAMAGE.] | |
|  | |
| ******************************************************************************/ | |
| 
 | |
| #include "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                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| typedef struct Conjuncts { | |
|     DdNode *g; | |
|     DdNode *h; | |
| } Conjuncts; | |
| 
 | |
| typedef struct  NodeStat { | |
|     int distance; | |
|     int localRef; | |
| } NodeStat; | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #ifndef lint | |
| static char rcsid[] DD_UNUSED = "$Id: cuddDecomp.c,v 1.45 2012/02/05 01:07:18 fabio Exp $"; | |
| #endif | |
|  | |
| static	DdNode	*one, *zero; | |
| long lastTimeG; | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| #define FactorsNotStored(factors)  ((int)((long)(factors) & 01)) | |
|  | |
| #define FactorsComplement(factors) ((Conjuncts *)((long)(factors) | 01)) | |
|  | |
| #define FactorsUncomplement(factors) ((Conjuncts *)((long)(factors) ^ 01)) | |
|  | |
| /**AutomaticStart*************************************************************/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static NodeStat * CreateBotDist (DdNode * node, st_table * distanceTable); | |
| static double CountMinterms (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 (DdNode * node, DdNode * g, DdNode * h, st_table * ghTable, st_table * cacheTable); | |
| static Conjuncts * PickOnePair (DdNode * node, DdNode * g1, DdNode * h1, DdNode * g2, DdNode * h2, st_table * ghTable, st_table * cacheTable); | |
| static Conjuncts * CheckInTables (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); | |
| static int cuddConjunctsAux (DdManager * dd, DdNode * f, DdNode ** c1, DdNode ** c2); | |
| 
 | |
| /**AutomaticEnd***************************************************************/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way conjunctive decomposition of a BDD.] | |
|  | |
|   Description [Performs two-way conjunctive decomposition of a | |
|   BDD. This procedure owes its name to the use of supersetting to | |
|   obtain an initial factor of the given function. Returns the number | |
|   of conjuncts produced, that is, 2 if successful; 1 if no meaningful | |
|   decomposition was found; 0 otherwise. The conjuncts produced by this | |
|   procedure tend to be imbalanced.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way disjunctive decomposition of a BDD.] | |
|  | |
|   Description [Performs two-way disjunctive decomposition of a BDD. | |
|   Returns the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. The | |
|   disjuncts produced by this procedure tend to be imbalanced.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way conjunctive decomposition of a BDD.] | |
|  | |
|   Description [Performs two-way conjunctive decomposition of a | |
|   BDD. This procedure owes its name to the iterated use of | |
|   supersetting to obtain a factor of the given function. Returns the | |
|   number of conjuncts produced, that is, 2 if successful; 1 if no | |
|   meaningful decomposition was found; 0 otherwise. The conjuncts | |
|   produced by this procedure tend to be imbalanced.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way disjunctive decomposition of a BDD.] | |
|  | |
|   Description [Performs two-way disjunctive decomposition of a BDD. | |
|   Returns the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. The | |
|   disjuncts produced by this procedure tend to be imbalanced.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way conjunctive decomposition of a BDD.] | |
|  | |
|   Description [Performs two-way conjunctive decomposition of a | |
|   BDD. This procedure owes its name to the fact tht it generalizes the | |
|   decomposition based on the cofactors with respect to one | |
|   variable. Returns the number of conjuncts produced, that is, 2 if | |
|   successful; 1 if no meaningful decomposition was found; 0 | |
|   otherwise. The conjuncts produced by this procedure tend to be | |
|   balanced.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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; | |
| 
 | |
|     one = DD_ONE(dd); | |
|     zero = Cudd_Not(one); | |
|      | |
|     do { | |
| 	dd->reordered = 0; | |
| 	result = cuddConjunctsAux(dd, f, &glocal, &hlocal); | |
|     } while (dd->reordered == 1); | |
| 
 | |
|     if (result == 0) { | |
| 	return(0); | |
|     } | |
| 
 | |
|     if (glocal != one) { | |
| 	if (hlocal != one) { | |
| 	    *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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way disjunctive decomposition of a BDD.] | |
|  | |
|   Description [Performs two-way disjunctive decomposition of a BDD. | |
|   Returns the number of disjuncts produced, that is, 2 if successful; | |
|   1 if no meaningful decomposition was found; 0 otherwise. The | |
|   disjuncts produced by this procedure tend to be balanced.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way conjunctive decomposition of a BDD.] | |
|  | |
|   Description [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.  Returns the | |
|   number of conjuncts produced, that is, 2 if successful; 1 if no | |
|   meaningful decomposition was found; 0 otherwise.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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_IsConstant(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_IsConstant(scan)) { | |
| 	int i = scan->index; | |
| 	int est1 = Cudd_EstimateCofactor(dd,f,i,1); | |
| 	int est0 = Cudd_EstimateCofactor(dd,f,i,0); | |
| 	/* Minimize the size of the larger of the two cofactors. */ | |
| 	int 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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs two-way disjunctive decomposition of a BDD.] | |
|  | |
|   Description [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.  Returns the | |
|   number of disjuncts produced, that is, 2 if successful; 1 if no | |
|   meaningful decomposition was found; 0 otherwise.] | |
|  | |
|   SideEffects [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.] | |
|  | |
|   SeeAlso     [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                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Get longest distance of node from constant.] | |
|  | |
|   Description [Get longest distance of node from constant. Returns the | |
|   distance of the root from the constant if successful; CUDD_OUT_OF_MEM | |
|   otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static NodeStat * | |
| CreateBotDist( | |
|   DdNode * node, | |
|   st_table * distanceTable) | |
| { | |
|     DdNode *N, *Nv, *Nnv; | |
|     int distance, distanceNv, distanceNnv; | |
|     NodeStat *nodeStat, *nodeStatNv, *nodeStatNnv; | |
| 
 | |
| #if 0 | |
|     if (Cudd_IsConstant(node)) { | |
| 	return(0); | |
|     } | |
| #endif | |
|      | |
|     /* Return the entry in the table if found. */ | |
|     N = Cudd_Regular(node); | |
|     if (st_lookup(distanceTable, N, &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, (char *)N, (char *)nodeStat) == | |
| 	ST_OUT_OF_MEM) { | |
| 	return(0); | |
| 
 | |
|     } | |
|     return(nodeStat); | |
| 
 | |
| } /* end of CreateBotDist */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Count the number of minterms of each node ina a BDD and | |
|   store it in a hash table.] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static double | |
| CountMinterms( | |
|   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 == zero) { | |
| 	    return(0); | |
| 	} else { | |
| 	    return(max); | |
| 	} | |
|     } | |
| 
 | |
|     /* Return the entry in the table if found. */ | |
|     if (st_lookup(mintermTable, node, &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(Nv, max, mintermTable, fp); | |
|     if (minNv == -1.0) return(-1.0); | |
|     minNnv = CountMinterms(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, (char *)node, (char *)dummy) == ST_OUT_OF_MEM) { | |
| 	(void) fprintf(fp, "st table insert failed\n"); | |
|     } | |
|     return(min); | |
| 
 | |
| } /* end of CountMinterms */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Free factors structure] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ConjunctsFree( | |
|   DdManager * dd, | |
|   Conjuncts * factors) | |
| { | |
|     Cudd_RecursiveDeref(dd, factors->g); | |
|     Cudd_RecursiveDeref(dd, factors->h); | |
|     FREE(factors); | |
|     return; | |
| 
 | |
| } /* end of ConjunctsFree */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Check whether the given pair is in the tables.] | |
|  | |
|   Description [.Check whether the given pair is in the tables.  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; ] | |
|  | |
|   SideEffects [] | |
|  | |
|   SeeAlso     [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, (char *)Cudd_Regular(g), &valueG); | |
|     hPresent = st_lookup_int(ghTable, (char *)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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Check the tables for the existence of pair and return one | |
|   combination, cache the result.] | |
|  | |
|   Description [Check the tables for the existence of pair and return | |
|   one combination, cache the result. The assumption is that one of the | |
|   conjuncts is already in the tables.] | |
|  | |
|   SideEffects [g and h referenced for the cache] | |
|  | |
|   SeeAlso     [ZeroCase] | |
|  | |
| ******************************************************************************/ | |
| static Conjuncts * | |
| CheckTablesCacheAndReturn( | |
|   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 != one) { | |
| 	    value = 0; | |
| 	    if (st_lookup_int(ghTable, (char *)Cudd_Regular(g), &value)) { | |
| 		value |= 1; | |
| 	    } else { | |
| 		value = 1; | |
| 	    } | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g), | |
| 			  (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = g; | |
| 	factors->h = h; | |
|     } else  if ((pairValue == BOTH_G) || (pairValue == G_ST)) { | |
| 	if (h != one) { | |
| 	    value = 0; | |
| 	    if (st_lookup_int(ghTable, (char *)Cudd_Regular(h), &value)) { | |
| 		value |= 2; | |
| 	    } else { | |
| 		value = 2; | |
| 	    } | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h), | |
| 			  (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = g; | |
| 	factors->h = h; | |
|     } else if (pairValue == H_CR) { | |
| 	if (g != one) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g), | |
| 			  (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	factors->g = h; | |
| 	factors->h = g; | |
|     } else if (pairValue == G_CR) { | |
| 	if (h != one) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h), | |
| 			  (char *)(long)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, (char *)node, (char *)factors) == ST_OUT_OF_MEM) { | |
| 	FREE(factors); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     return(factors); | |
| 
 | |
| } /* end of CheckTablesCacheAndReturn */ | |
| 	 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Check the tables for the existence of pair and return one | |
|   combination, store in cache.] | |
|  | |
|   Description [Check the tables for the existence of pair and return | |
|   one combination, store in cache. 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. ] | |
|  | |
|   SideEffects [] | |
|  | |
|   SeeAlso     [ZeroCase BuildConjuncts] | |
|  | |
| ******************************************************************************/ | |
| static Conjuncts * | |
| PickOnePair( | |
|   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 == one) { | |
| 	twoRef = (Cudd_Regular(g2))->ref; | |
|     } else if (g2 == one) { | |
| 	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 == one) { | |
| 	oneRef  = (Cudd_Regular(g1))->ref; | |
|     } else if (g1 == one) { | |
| 	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 != one) { | |
| 	/* insert g in htable */ | |
| 	value = 0; | |
| 	if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->g), &value)) { | |
| 	    if (value == 2) { | |
| 		value |= 1; | |
| 		if (st_insert(ghTable, (char *)Cudd_Regular(factors->g), | |
| 			      (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		    FREE(factors); | |
| 		    return(NULL); | |
| 		} | |
| 	    } | |
| 	} else { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(factors->g), | |
| 			  (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
| 
 | |
|     if (factors->h != one) { | |
| 	/* insert h in htable */ | |
| 	value = 0; | |
| 	if (st_lookup_int(ghTable, (char *)Cudd_Regular(factors->h), &value)) { | |
| 	    if (value == 1) { | |
| 		value |= 2; | |
| 		if (st_insert(ghTable, (char *)Cudd_Regular(factors->h), | |
| 			      (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		    FREE(factors); | |
| 		    return(NULL); | |
| 		} | |
| 	    }	     | |
| 	} else { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(factors->h), | |
| 			  (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
|      | |
|     /* Store factors in cache table for later use. */ | |
|     if (st_insert(cacheTable, (char *)node, (char *)factors) == | |
| 	    ST_OUT_OF_MEM) { | |
| 	FREE(factors); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     return(factors); | |
| 
 | |
| } /* end of PickOnePair */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Check if the two pairs exist in the table, If any of the | |
|   conjuncts do exist, store in the cache and return the corresponding pair.] | |
|  | |
|   Description [Check if the two pairs exist in the table. If any of | |
|   the conjuncts do exist, store in the cache and return the | |
|   corresponding pair.] | |
|  | |
|   SideEffects [] | |
|  | |
|   SeeAlso     [ZeroCase BuildConjuncts] | |
|  | |
| ******************************************************************************/ | |
| static Conjuncts * | |
| CheckInTables( | |
|   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 != one) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h1), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h1), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g1), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g1), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h2), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h2), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g2), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 3; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g2), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h1), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g1), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 1; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(h2), | |
| 			  (char *)(long)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 != one) { | |
| 	    value = 2; | |
| 	    if (st_insert(ghTable, (char *)Cudd_Regular(g2), | |
| 			  (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 		*outOfMem = 1; | |
| 		FREE(factors); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
|      | |
|     /* Store factors in cache table for later use. */ | |
|     if (st_insert(cacheTable, (char *)node, (char *)factors) == | |
| 	    ST_OUT_OF_MEM) { | |
| 	*outOfMem = 1; | |
| 	FREE(factors); | |
| 	return(NULL); | |
|     } | |
|     return factors; | |
| } /* end of CheckInTables */ | |
| 
 | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [If one child is zero, do explicitly what Restrict does or better] | |
|  | |
|   Description [If one child is zero, do explicitly what Restrict does or better. | |
|   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.] | |
|  | |
|   SideEffects [Frees the BDDs in factorsNv. factorsNv itself is not freed | |
|   because it is freed above.] | |
|  | |
|   SeeAlso     [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 == one) { | |
| 	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, (char *)node, (char *)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, (char *)Cudd_Regular(x), &value)) { | |
| 	    value |= 1; | |
| 	} else { | |
| 	    value = 1; | |
| 	} | |
| 	if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)value) == ST_OUT_OF_MEM) { | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return NULL; | |
| 	} | |
| 	return(factors); | |
|     } | |
|      | |
|     /* Seprate variable and child */ | |
|     if (factorsNv->h == one) { | |
| 	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, (char *)node, (char *)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, (char *)Cudd_Regular(x), &value)) { | |
| 	    value |= 2; | |
| 	} else { | |
| 	    value = 2; | |
| 	} | |
| 	if (st_insert(ghTable, (char *)Cudd_Regular(x), (char *)(long)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 == zero) || (Gnv == zero)) { | |
| 	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(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 == zero) || (Hnv == zero)) { | |
| 	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(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(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(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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Builds the conjuncts recursively, bottom up.] | |
|  | |
|   Description [Builds the conjuncts recursively, bottom up. 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 3.] | |
|  | |
|   SideEffects [] | |
|  | |
|   SeeAlso     [cuddConjunctsAux] | |
|  | |
| ******************************************************************************/ | |
| static Conjuncts * | |
| BuildConjuncts( | |
|   DdManager * dd, | |
|   DdNode * node, | |
|   st_table * distanceTable, | |
|   st_table * cacheTable, | |
|   int approxDistance, | |
|   int maxLocalRef, | |
|   st_table * ghTable, | |
|   st_table * mintermTable) | |
| { | |
|     int topid, distance; | |
|     Conjuncts *factorsNv, *factorsNnv, *factors; | |
|     Conjuncts *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; | |
| 
 | |
|     /* if f is constant, return (f,f) */ | |
|     if (Cudd_IsConstant(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 = dummy; | |
| 	return(factors); | |
|     } | |
|      | |
|     /* check distance and local reference count of this node */ | |
|     N = Cudd_Regular(node); | |
|     if (!st_lookup(distanceTable, N, &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, (char *)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, (char *)Cudd_Regular(node), (char *)(long)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, (char *)Cudd_Regular(node), (char *)(long)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_IsConstant(Nv)) { | |
| 	if (!st_lookup(mintermTable, Nv, &doubleDummy)) { | |
| 	    (void) fprintf(dd->err, "Not in table: Something wrong\n"); | |
| 	    dd->errorCode = CUDD_INTERNAL_ERROR; | |
| 	    return(NULL); | |
| 	} | |
| 	minNv = *doubleDummy; | |
|     } | |
|      | |
|     if (!Cudd_IsConstant(Nnv)) { | |
| 	if (!st_lookup(mintermTable, Nnv, &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); | |
| 	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); | |
| 	if (factorsNnv == 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(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(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 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Procedure to compute two conjunctive factors of f and place in *c1 and *c2.] | |
|  | |
|   Description [Procedure to compute two conjunctive factors of f and | |
|   place in *c1 and *c2. Sets up the required data - table of distances | |
|   from the constant and local reference count. Also minterm table. ] | |
|  | |
|   SideEffects [] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| 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; | |
|      | |
|     /* 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, (char *)one, (char *)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, (char **)&key, (char **)&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, (char **)&key, (char **)&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(f, max, mintermTable, dd->err); | |
|     if (minterms == -1.0) goto outOfMem; | |
|      | |
|     lastTimeG = Cudd_Random() & 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); | |
|     if (factors == NULL) goto outOfMem; | |
| 
 | |
|     /* free up tables */ | |
|     stGen = st_init_gen(distanceTable); | |
|     if (stGen == NULL) goto outOfMem; | |
|     while(st_gen(stGen, (char **)&key, (char **)&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, (char **)&key, (char **)&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_IsConstant(f))) { | |
| 	    assert(*c2 == one); | |
| 	} | |
| 	if ((*c2 == f) && (!Cudd_IsConstant(f))) { | |
| 	    assert(*c1 == one); | |
| 	} | |
| 	 | |
| 	if ((*c1 != one) && (!Cudd_IsConstant(f))) { | |
| 	    assert(!Cudd_bddLeq(dd, *c2, *c1)); | |
| 	} | |
| 	if ((*c2 != one) && (!Cudd_IsConstant(f))) { | |
| 	    assert(!Cudd_bddLeq(dd, *c1, *c2)); | |
| 	} | |
| #endif | |
|     } | |
| 
 | |
|     stGen = st_init_gen(cacheTable); | |
|     if (stGen == NULL) goto outOfMem; | |
|     while(st_gen(stGen, (char **)&key, (char **)&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, (char **)&key, (char **)&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, (char **)&key, (char **)&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, (char **)&key, (char **)&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 */
 |