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.
		
		
		
		
		
			
		
			
				
					
					
						
							1419 lines
						
					
					
						
							39 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1419 lines
						
					
					
						
							39 KiB
						
					
					
				| /** | |
|   @file | |
|  | |
|   @ingroup cudd | |
|  | |
|   @brief Functions for the detection of essential variables. | |
|  | |
|   @author 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                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /* These definitions are for the bit vectors. */ | |
| #if SIZEOF_VOID_P == 8 | |
| #define BPL 64 | |
| #define LOGBPL 6 | |
| #else | |
| #define BPL 32 | |
| #define LOGBPL 5 | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** | |
| ** @brief This structure holds the set of clauses for a node. | |
| ** @details Each clause consists of two literals. | |
| ** For one-literal clauses, the second literal is FALSE. | |
| ** Each literal is composed of a variable and a phase.  A variable is a node | |
| ** index, and requires sizeof(DdHalfWord) bytes.  The constant literals use | |
| ** CUDD_MAXINDEX as variable indicator.  Each phase is a bit: 0 for positive | |
| ** phase, and 1 for negative phase. | |
| ** Variables and phases are stored separately for the sake of compactness. | |
| ** The variables are stored in an array of DdHalfWord's terminated by a | |
| ** sentinel (a pair of zeroes).  The phases are stored in a bit vector. | |
| ** The cnt field holds, at the end, the number of clauses. | |
| ** The clauses of the set are kept sorted.  For each clause, the first literal | |
| ** is the one of least index.  So, the clause with literals +2 and -4 is stored | |
| ** as (+2,-4).  A one-literal clause with literal +3 is stored as | |
| ** (+3,-CUDD_MAXINDEX).  Clauses are sorted in decreasing order as follows: | |
| ** <ul> | |
| ** <li> (+5,-7) | |
| ** <li> (+5,+6) | |
| ** <li> (-5,+7) | |
| ** <li> (-4,FALSE) | |
| ** <li> (-4,+8) | |
| ** <li> ... | |
| ** </ul> | |
| ** That is, one first looks at the variable of the first literal, then at the | |
| ** phase of the first literal, then at the variable of the second literal, | |
| ** and finally at the phase of the second literal. | |
| */ | |
| struct DdTlcInfo { | |
|     DdHalfWord *vars; | |
|     ptruint *phases; | |
|     DdHalfWord cnt; | |
| }; | |
| 
 | |
| /** | |
| ** @brief This structure is for temporary representation of sets of clauses. | |
| ** @details It is meant to be used in linked lists, when the number of clauses | |
| ** is not yet known.  The encoding of a clause is the same as in DdTlcInfo, | |
| ** though the phase information is not stored in a bit array. | |
| */ | |
| struct TlClause { | |
|     DdHalfWord v1, v2; | |
|     short p1, p2; | |
|     struct TlClause *next; | |
| }; | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| typedef ptruint BitVector; | |
| typedef struct TlClause TlClause; | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /** \cond */ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static DdNode * ddFindEssentialRecur (DdManager *dd, DdNode *f); | |
| static DdTlcInfo * ddFindTwoLiteralClausesRecur (DdManager * dd, DdNode * f, st_table *table, BitVector *Tolv, BitVector *Tolp, BitVector *Eolv, BitVector *Eolp); | |
| static DdTlcInfo * computeClauses (DdTlcInfo *Tres, DdTlcInfo *Eres, DdHalfWord label, int size, BitVector *Tolv, BitVector *Tolp, BitVector *Eolv, BitVector *Eolp); | |
| static DdTlcInfo * computeClausesWithUniverse (DdTlcInfo *Cres, DdHalfWord label, short phase); | |
| static DdTlcInfo * emptyClauseSet (void); | |
| static int sentinelp (DdHalfWord var1, DdHalfWord var2); | |
| static int equalp (DdHalfWord var1a, short phase1a, DdHalfWord var1b, short phase1b, DdHalfWord var2a, short phase2a, DdHalfWord var2b, short phase2b); | |
| static int beforep (DdHalfWord var1a, short phase1a, DdHalfWord var1b, short phase1b, DdHalfWord var2a, short phase2a, DdHalfWord var2b, short phase2b); | |
| static int oneliteralp (DdHalfWord var); | |
| static int impliedp (DdHalfWord var1, short phase1, DdHalfWord var2, short phase2, BitVector *olv, BitVector *olp); | |
| static BitVector * bitVectorAlloc (int size); | |
| static void bitVectorClear (BitVector *vector, int size); | |
| static void bitVectorFree (BitVector *vector); | |
| static short bitVectorRead (BitVector *vector, int i); | |
| static void bitVectorSet (BitVector * vector, int i, short val); | |
| static DdTlcInfo * tlcInfoAlloc (void); | |
| 
 | |
| /** \endcond */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Finds the essential variables of a %DD. | |
|  | |
|   @details Returns the cube of the essential variables. A positive | |
|   literal means that the variable must be set to 1 for the function to be | |
|   1. A negative literal means that the variable must be set to 0 for the | |
|   function to be 1. | |
|  | |
|   @return a pointer to the cube %BDD if successful; NULL otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_bddIsVarEssential | |
|  | |
| */ | |
| DdNode * | |
| Cudd_FindEssential( | |
|   DdManager * dd, | |
|   DdNode * f) | |
| { | |
|     DdNode *res; | |
| 
 | |
|     do { | |
| 	dd->reordered = 0; | |
| 	res = ddFindEssentialRecur(dd,f); | |
|     } while (dd->reordered == 1); | |
|     if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) { | |
|         dd->timeoutHandler(dd, dd->tohArg); | |
|     } | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_FindEssential */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Determines whether a given variable is essential with a | |
|   given phase in a %BDD. | |
|  | |
|   @details Uses Cudd_bddIteConstant. Returns 1 if phase == 1 and | |
|   f-->x_id, or if phase == 0 and f-->x_id'. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_FindEssential | |
|  | |
| */ | |
| int | |
| Cudd_bddIsVarEssential( | |
|   DdManager * manager, | |
|   DdNode * f, | |
|   int  id, | |
|   int  phase) | |
| { | |
|     DdNode	*var; | |
|     int		res; | |
| 
 | |
|     var = Cudd_bddIthVar(manager, id); | |
| 
 | |
|     var = Cudd_NotCond(var,phase == 0); | |
| 
 | |
|     res = Cudd_bddLeq(manager, f, var); | |
| 
 | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_bddIsVarEssential */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Finds the two literal clauses of a %DD. | |
|  | |
|   @details Returns the one- and two-literal clauses of a %DD.  For a | |
|   constant %DD, the empty set of clauses is returned.  This is | |
|   obviously correct for a non-zero constant.  For the constant zero, | |
|   it is based on the assumption that only those clauses containing | |
|   variables in the support of the function are considered.  Since the | |
|   support of a constant function is empty, no clauses are returned. | |
|  | |
|   @return a pointer to the structure holding the clauses if | |
|   successful; NULL otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_FindEssential | |
|  | |
| */ | |
| DdTlcInfo * | |
| Cudd_FindTwoLiteralClauses( | |
|   DdManager * dd, | |
|   DdNode * f) | |
| { | |
|     DdTlcInfo *res; | |
|     st_table *table; | |
|     st_generator *gen; | |
|     DdTlcInfo *tlc; | |
|     DdNode *node; | |
|     int size = dd->size; | |
|     BitVector *Tolv, *Tolp, *Eolv, *Eolp; | |
| 
 | |
|     if (Cudd_IsConstantInt(f)) { | |
| 	res = emptyClauseSet(); | |
| 	return(res); | |
|     } | |
|     table = st_init_table(st_ptrcmp,st_ptrhash); | |
|     if (table == NULL) return(NULL); | |
|     Tolv = bitVectorAlloc(size); | |
|     if (Tolv == NULL) { | |
| 	st_free_table(table); | |
| 	return(NULL); | |
|     } | |
|     Tolp = bitVectorAlloc(size); | |
|     if (Tolp == NULL) { | |
| 	st_free_table(table); | |
| 	bitVectorFree(Tolv); | |
| 	return(NULL); | |
|     } | |
|     Eolv = bitVectorAlloc(size); | |
|     if (Eolv == NULL) { | |
| 	st_free_table(table); | |
| 	bitVectorFree(Tolv); | |
| 	bitVectorFree(Tolp); | |
| 	return(NULL); | |
|     } | |
|     Eolp = bitVectorAlloc(size); | |
|     if (Eolp == NULL) { | |
| 	st_free_table(table); | |
| 	bitVectorFree(Tolv); | |
| 	bitVectorFree(Tolp); | |
| 	bitVectorFree(Eolv); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     res = ddFindTwoLiteralClausesRecur(dd,f,table,Tolv,Tolp,Eolv,Eolp); | |
|     /* Dispose of table contents and free table. */ | |
|     st_foreach_item(table, gen, (void **) &node, (void **) &tlc) { | |
| 	if (node != f) { | |
| 	    Cudd_tlcInfoFree(tlc); | |
| 	} | |
|     } | |
|     st_free_table(table); | |
|     bitVectorFree(Tolv); | |
|     bitVectorFree(Tolp); | |
|     bitVectorFree(Eolv); | |
|     bitVectorFree(Eolp); | |
| 
 | |
|     if (res != NULL) { | |
| 	int i; | |
| 	for (i = 0; !sentinelp(res->vars[i], res->vars[i+1]); i += 2); | |
| 	res->cnt = i >> 1; | |
|     } | |
| 
 | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_FindTwoLiteralClauses */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Accesses the i-th clause of a %DD. | |
|  | |
|   @details Accesses the i-th clause of a %DD given the clause set which | |
|   must be already computed. | |
|  | |
|   @return 1 if successful; 0 if i is out of range, or in case of | |
|   error. | |
|  | |
|   @sideeffect the four components of a clause are returned as side effects. | |
|  | |
|   @see Cudd_FindTwoLiteralClauses | |
|  | |
| */ | |
| int | |
| Cudd_ReadIthClause( | |
|   DdTlcInfo * tlc, | |
|   int i, | |
|   unsigned *var1, | |
|   unsigned *var2, | |
|   int *phase1, | |
|   int *phase2) | |
| { | |
|     if (tlc == NULL) return(0); | |
|     if (tlc->vars == NULL || tlc->phases == NULL) return(0); | |
|     if (i < 0 || (unsigned) i >= tlc->cnt) return(0); | |
|     *var1 = (unsigned) tlc->vars[2*i]; | |
|     *var2 = (unsigned) tlc->vars[2*i+1]; | |
|     *phase1 = (int) bitVectorRead(tlc->phases, 2*i); | |
|     *phase2 = (int) bitVectorRead(tlc->phases, 2*i+1); | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_ReadIthClause */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Prints the one- and two-literal clauses of a %DD. | |
|  | |
|   @details The argument "names" can be NULL, in which case the | |
|   variable indices are printed. | |
|  | |
|   @return 1 if successful; 0 otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_FindTwoLiteralClauses | |
|  | |
| */ | |
| int | |
| Cudd_PrintTwoLiteralClauses( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   char **names, | |
|   FILE *fp) | |
| { | |
|     DdHalfWord *vars; | |
|     BitVector *phases; | |
|     int i; | |
|     DdTlcInfo *res = Cudd_FindTwoLiteralClauses(dd, f); | |
|     FILE *ifp = fp == NULL ? dd->out : fp; | |
| 
 | |
|     if (res == NULL) return(0); | |
|     vars = res->vars; | |
|     phases = res->phases; | |
|     for (i = 0; !sentinelp(vars[i], vars[i+1]); i += 2) { | |
| 	if (names != NULL) { | |
| 	    if (vars[i+1] == CUDD_MAXINDEX) { | |
| 		(void) fprintf(ifp, "%s%s\n", | |
| 			       bitVectorRead(phases, i) ? "~" : " ", | |
| 			       names[vars[i]]); | |
| 	    } else { | |
| 		(void) fprintf(ifp, "%s%s | %s%s\n", | |
| 			       bitVectorRead(phases, i) ? "~" : " ", | |
| 			       names[vars[i]], | |
| 			       bitVectorRead(phases, i+1) ? "~" : " ", | |
| 			       names[vars[i+1]]); | |
| 	    } | |
| 	} else { | |
| 	    if (vars[i+1] == CUDD_MAXINDEX) { | |
| 		(void) fprintf(ifp, "%s%d\n", | |
| 			       bitVectorRead(phases, i) ? "~" : " ", | |
| 			       (int) vars[i]); | |
| 	    } else { | |
| 		(void) fprintf(ifp, "%s%d | %s%d\n", | |
| 			       bitVectorRead(phases, i) ? "~" : " ", | |
| 			       (int) vars[i], | |
| 			       bitVectorRead(phases, i+1) ? "~" : " ", | |
| 			       (int) vars[i+1]); | |
| 	    } | |
| 	} | |
|     } | |
|     Cudd_tlcInfoFree(res); | |
| 
 | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_PrintTwoLiteralClauses */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Frees a DdTlcInfo Structure. | |
|  | |
|   @details Also frees the memory pointed by it. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| void | |
| Cudd_tlcInfoFree( | |
|   DdTlcInfo * t) | |
| { | |
|     if (t->vars != NULL) FREE(t->vars); | |
|     if (t->phases != NULL) FREE(t->phases); | |
|     FREE(t); | |
| 
 | |
| } /* end of Cudd_tlcInfoFree */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Implements the recursive step of Cudd_FindEssential. | |
|  | |
|   @return a pointer to the cube %BDD if successful; NULL otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static DdNode * | |
| ddFindEssentialRecur( | |
|   DdManager * dd, | |
|   DdNode * f) | |
| { | |
|     DdNode	*T, *E, *F; | |
|     DdNode	*essT, *essE, *res; | |
|     unsigned	index; | |
|     DdNode	*one, *lzero, *azero; | |
| 
 | |
|     one = DD_ONE(dd); | |
|     F = Cudd_Regular(f); | |
|     /* If f is constant the set of essential variables is empty. */ | |
|     if (cuddIsConstant(F)) return(one); | |
| 
 | |
|     res = cuddCacheLookup1(dd,Cudd_FindEssential,f); | |
|     if (res != NULL) { | |
| 	return(res); | |
|     } | |
| 
 | |
|     checkWhetherToGiveUp(dd); | |
| 
 | |
|     lzero = Cudd_Not(one); | |
|     azero = DD_ZERO(dd); | |
|     /* Find cofactors: here f is non-constant. */ | |
|     T = cuddT(F); | |
|     E = cuddE(F); | |
|     if (Cudd_IsComplement(f)) { | |
| 	T = Cudd_Not(T); E = Cudd_Not(E); | |
|     } | |
| 
 | |
|     index = F->index; | |
|     if (Cudd_IsConstantInt(T) && T != lzero && T != azero) { | |
| 	/* if E is zero, index is essential, otherwise there are no | |
| 	** essentials, because index is not essential and no other variable | |
| 	** can be, since setting index = 1 makes the function constant and | |
| 	** different from 0. | |
| 	*/ | |
| 	if (E == lzero || E == azero) { | |
| 	    res = dd->vars[index]; | |
| 	} else { | |
| 	    res = one; | |
| 	} | |
|     } else if (T == lzero || T == azero) { | |
| 	if (Cudd_IsConstantInt(E)) { /* E cannot be zero here */ | |
| 	    res = Cudd_Not(dd->vars[index]); | |
| 	} else { /* E == non-constant */ | |
| 	    /* find essentials in the else branch */ | |
| 	    essE = ddFindEssentialRecur(dd,E); | |
| 	    if (essE == NULL) { | |
| 		return(NULL); | |
| 	    } | |
| 	    cuddRef(essE); | |
| 
 | |
| 	    /* add index to the set with negative phase */ | |
| 	    res = cuddUniqueInter(dd,index,one,Cudd_Not(essE)); | |
| 	    if (res == NULL) { | |
| 		Cudd_RecursiveDeref(dd,essE); | |
| 		return(NULL); | |
| 	    } | |
| 	    res = Cudd_Not(res); | |
| 	    cuddDeref(essE); | |
| 	} | |
|     } else { /* T == non-const */ | |
| 	if (E == lzero || E == azero) { | |
| 	    /* find essentials in the then branch */ | |
| 	    essT = ddFindEssentialRecur(dd,T); | |
| 	    if (essT == NULL) { | |
| 		return(NULL); | |
| 	    } | |
| 	    cuddRef(essT); | |
| 
 | |
| 	    /* add index to the set with positive phase */ | |
| 	    /* use And because essT may be complemented */ | |
| 	    res = cuddBddAndRecur(dd,dd->vars[index],essT); | |
| 	    if (res == NULL) { | |
| 		Cudd_RecursiveDeref(dd,essT); | |
| 		return(NULL); | |
| 	    } | |
| 	    cuddDeref(essT); | |
| 	} else if (!Cudd_IsConstantInt(E)) { | |
| 	    /* if E is a non-zero constant there are no essentials | |
| 	    ** because T is non-constant. | |
| 	    */ | |
| 	    essT = ddFindEssentialRecur(dd,T); | |
| 	    if (essT == NULL) { | |
| 		return(NULL); | |
| 	    } | |
| 	    if (essT == one) { | |
| 		res = one; | |
| 	    } else { | |
| 		cuddRef(essT); | |
| 		essE = ddFindEssentialRecur(dd,E); | |
| 		if (essE == NULL) { | |
| 		    Cudd_RecursiveDeref(dd,essT); | |
| 		    return(NULL); | |
| 		} | |
| 		cuddRef(essE); | |
| 
 | |
| 		/* res = intersection(essT, essE) */ | |
| 		res = cuddBddLiteralSetIntersectionRecur(dd,essT,essE); | |
| 		if (res == NULL) { | |
| 		    Cudd_RecursiveDeref(dd,essT); | |
| 		    Cudd_RecursiveDeref(dd,essE); | |
| 		    return(NULL); | |
| 		} | |
| 		cuddRef(res); | |
| 		Cudd_RecursiveDeref(dd,essT); | |
| 		Cudd_RecursiveDeref(dd,essE); | |
| 		cuddDeref(res); | |
| 	    } | |
| 	} else {	/* E is a non-zero constant */ | |
| 	    res = one; | |
| 	} | |
|     } | |
| 
 | |
|     cuddCacheInsert1(dd,Cudd_FindEssential, f, res); | |
|     return(res); | |
| 
 | |
| } /* end of ddFindEssentialRecur */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Implements the recursive step of Cudd_FindTwoLiteralClauses. | |
|  | |
|   @details The %DD node is assumed to be not constant. | |
|  | |
|   @return a pointer to a set of clauses if successful; NULL otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_FindTwoLiteralClauses | |
|  | |
| */ | |
| static DdTlcInfo * | |
| ddFindTwoLiteralClausesRecur( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   st_table *table, | |
|   BitVector *Tolv, | |
|   BitVector *Tolp, | |
|   BitVector *Eolv, | |
|   BitVector *Eolp) | |
| { | |
|     DdNode *T, *E, *F; | |
|     DdNode *one, *lzero, *azero; | |
|     DdTlcInfo *res, *Tres, *Eres; | |
|     DdHalfWord index; | |
| 
 | |
|     F = Cudd_Regular(f); | |
| 
 | |
|     assert(!cuddIsConstant(F)); | |
| 
 | |
|     /* Check computed table.  Separate entries are necessary for | |
|     ** a node and its complement.  We should update the counter here. */ | |
|     if (st_lookup(table, f, (void **) &res)) { | |
| 	return(res); | |
|     } | |
| 
 | |
|     /* Easy access to the constants for BDDs and ADDs. */ | |
|     one = DD_ONE(dd); | |
|     lzero = Cudd_Not(one); | |
|     azero = DD_ZERO(dd); | |
| 
 | |
|     /* Find cofactors and variable labeling the top node. */ | |
|     T = cuddT(F); E = cuddE(F); | |
|     if (Cudd_IsComplement(f)) { | |
| 	T = Cudd_Not(T); E = Cudd_Not(E); | |
|     } | |
|     index = F->index; | |
| 
 | |
|     if (Cudd_IsConstantInt(T) && T != lzero && T != azero) { | |
| 	/* T is a non-zero constant.  If E is zero, then this node's index | |
| 	** is a one-literal clause.  Otherwise, if E is a non-zero | |
| 	** constant, there are no clauses for this node.  Finally, | |
| 	** if E is not constant, we recursively compute its clauses, and then | |
| 	** merge using the empty set for T. */ | |
| 	if (E == lzero || E == azero) { | |
| 	    /* Create the clause (index + 0). */ | |
| 	    res = tlcInfoAlloc(); | |
| 	    if (res == NULL) return(NULL); | |
| 	    res->vars = ALLOC(DdHalfWord,4); | |
| 	    if (res->vars == NULL) { | |
| 		FREE(res); | |
| 		return(NULL); | |
| 	    } | |
| 	    res->phases = bitVectorAlloc(2); | |
| 	    if (res->phases == NULL) { | |
| 		FREE(res->vars); | |
| 		FREE(res); | |
| 		return(NULL); | |
| 	    } | |
| 	    res->vars[0] = index; | |
| 	    res->vars[1] = CUDD_MAXINDEX; | |
| 	    res->vars[2] = 0; | |
| 	    res->vars[3] = 0; | |
| 	    bitVectorSet(res->phases, 0, 0); /* positive phase */ | |
| 	    bitVectorSet(res->phases, 1, 1); /* negative phase */ | |
| 	} else if (Cudd_IsConstantInt(E)) { | |
| 	    /* If E is a non-zero constant, no clauses. */ | |
| 	    res = emptyClauseSet(); | |
| 	} else { | |
| 	    /* E is non-constant */ | |
| 	    Tres = emptyClauseSet(); | |
| 	    if (Tres == NULL) return(NULL); | |
| 	    Eres = ddFindTwoLiteralClausesRecur(dd, E, table, | |
|                                                 Tolv, Tolp, Eolv, Eolp); | |
| 	    if (Eres == NULL) { | |
| 		Cudd_tlcInfoFree(Tres); | |
| 		return(NULL); | |
| 	    } | |
| 	    res = computeClauses(Tres, Eres, index, dd->size, | |
|                                  Tolv, Tolp, Eolv, Eolp); | |
| 	    Cudd_tlcInfoFree(Tres); | |
| 	} | |
|     } else if (T == lzero || T == azero) { | |
| 	/* T is zero.  If E is a non-zero constant, then the | |
| 	** complement of this node's index is a one-literal clause. | |
| 	** Otherwise, if E is not constant, we recursively compute its | |
| 	** clauses, and then merge using the universal set for T. */ | |
| 	if (Cudd_IsConstantInt(E)) { /* E cannot be zero here */ | |
| 	    /* Create the clause (!index + 0). */ | |
| 	    res = tlcInfoAlloc(); | |
| 	    if (res == NULL) return(NULL); | |
| 	    res->vars = ALLOC(DdHalfWord,4); | |
| 	    if (res->vars == NULL) { | |
| 		FREE(res); | |
| 		return(NULL); | |
| 	    } | |
| 	    res->phases = bitVectorAlloc(2); | |
| 	    if (res->phases == NULL) { | |
| 		FREE(res->vars); | |
| 		FREE(res); | |
| 		return(NULL); | |
| 	    } | |
| 	    res->vars[0] = index; | |
| 	    res->vars[1] = CUDD_MAXINDEX; | |
| 	    res->vars[2] = 0; | |
| 	    res->vars[3] = 0; | |
| 	    bitVectorSet(res->phases, 0, 1); /* negative phase */ | |
| 	    bitVectorSet(res->phases, 1, 1); /* negative phase */ | |
| 	} else { /* E == non-constant */ | |
| 	    Eres = ddFindTwoLiteralClausesRecur(dd, E, table, | |
|                                                 Tolv, Tolp, Eolv, Eolp); | |
| 	    if (Eres == NULL) return(NULL); | |
| 	    res = computeClausesWithUniverse(Eres, index, 1); | |
| 	} | |
|     } else { /* T == non-const */ | |
| 	Tres = ddFindTwoLiteralClausesRecur(dd, T, table, | |
|                                             Tolv, Tolp, Eolv, Eolp); | |
| 	if (Tres == NULL) return(NULL); | |
| 	if (Cudd_IsConstantInt(E)) { | |
| 	    if (E == lzero || E == azero) { | |
| 		res = computeClausesWithUniverse(Tres, index, 0); | |
| 	    } else { | |
| 		Eres = emptyClauseSet(); | |
| 		if (Eres == NULL) return(NULL); | |
| 		res = computeClauses(Tres, Eres, index, dd->size, | |
|                                      Tolv, Tolp, Eolv, Eolp); | |
| 		Cudd_tlcInfoFree(Eres); | |
| 	    } | |
| 	} else { | |
| 	    Eres = ddFindTwoLiteralClausesRecur(dd, E, table, | |
|                                                 Tolv, Tolp, Eolv, Eolp); | |
| 	    if (Eres == NULL) return(NULL); | |
| 	    res = computeClauses(Tres, Eres, index, dd->size, | |
|                                  Tolv, Tolp, Eolv, Eolp); | |
| 	} | |
|     } | |
| 
 | |
|     /* Cache results. */ | |
|     if (st_add_direct(table, f, res) == ST_OUT_OF_MEM) { | |
| 	FREE(res); | |
| 	return(NULL); | |
|     } | |
|     return(res); | |
| 
 | |
| } /* end of ddFindTwoLiteralClausesRecur */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Computes the two-literal clauses for a node. | |
|  | |
|   @details Computes the two-literal clauses for a node given the | |
|   clauses for its children and the label of the node. | |
|  | |
|   @return a pointer to a TclInfo structure if successful; NULL | |
|   otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see computeClausesWithUniverse | |
|  | |
| */ | |
| static DdTlcInfo * | |
| computeClauses( | |
|   DdTlcInfo *Tres /**< list of clauses for T child */, | |
|   DdTlcInfo *Eres /**< list of clauses for E child */, | |
|   DdHalfWord label /**< variable labeling the current node */, | |
|   int size /**< number of variables in the manager */, | |
|   BitVector *Tolv /**< variable bit vector for T child */, | |
|   BitVector *Tolp /**< phase bit vector for T child */, | |
|   BitVector *Eolv /**< variable bit vector for E child */, | |
|   BitVector *Eolp /**< phase bit vector for E child */) | |
| { | |
|     DdHalfWord *Tcv = Tres->vars; /* variables of clauses for the T child */ | |
|     BitVector *Tcp = Tres->phases; /* phases of clauses for the T child */ | |
|     DdHalfWord *Ecv = Eres->vars; /* variables of clauses for the E child */ | |
|     BitVector *Ecp = Eres->phases; /* phases of clauses for the E child */ | |
|     DdHalfWord *Vcv = NULL; /* pointer to variables of the clauses for v */ | |
|     BitVector *Vcp = NULL; /* pointer to phases of the clauses for v */ | |
|     DdTlcInfo *res = NULL; /* the set of clauses to be returned */ | |
|     int pt = 0; /* index in the list of clauses of T */ | |
|     int pe = 0; /* index in the list of clauses of E */ | |
|     int cv = 0; /* counter of the clauses for this node */ | |
|     TlClause *iclauses = NULL; /* list of inherited clauses */ | |
|     TlClause *tclauses = NULL; /* list of 1-literal clauses of T */ | |
|     TlClause *eclauses = NULL; /* list of 1-literal clauses of E */ | |
|     TlClause *nclauses = NULL; /* list of new (non-inherited) clauses */ | |
|     TlClause *lnclause = NULL; /* pointer to last new clause */ | |
|     TlClause *newclause; /* temporary pointer to new clauses */ | |
| 
 | |
|     /* Initialize sets of one-literal clauses.  The one-literal clauses | |
|     ** are stored redundantly.  These sets allow constant-time lookup, which | |
|     ** we need when we check for implication of a two-literal clause by a | |
|     ** one-literal clause.  The linked lists allow fast sequential | |
|     ** processing. */ | |
|     bitVectorClear(Tolv, size); | |
|     bitVectorClear(Tolp, size); | |
|     bitVectorClear(Eolv, size); | |
|     bitVectorClear(Eolp, size); | |
| 
 | |
|     /* Initialize result structure. */ | |
|     res = tlcInfoAlloc(); | |
|     if (res == NULL) goto cleanup; | |
| 
 | |
|     /* Scan the two input list.  Extract inherited two-literal clauses | |
|     ** and set aside one-literal clauses from each list.  The incoming lists | |
|     ** are sorted in the order defined by beforep.  The three linked list | |
|     ** produced by this loop are sorted in the reverse order because we | |
|     ** always append to the front of the lists. | |
|     ** The inherited clauses are those clauses (both one- and two-literal) | |
|     ** that are common to both children; and the two-literal clauses of | |
|     ** one child that are implied by a one-literal clause of the other | |
|     ** child. */ | |
|     while (!sentinelp(Tcv[pt], Tcv[pt+1]) || !sentinelp(Ecv[pe], Ecv[pe+1])) { | |
| 	if (equalp(Tcv[pt], bitVectorRead(Tcp, pt), | |
| 		   Tcv[pt+1], bitVectorRead(Tcp, pt+1), | |
| 		   Ecv[pe], bitVectorRead(Ecp, pe), | |
| 		   Ecv[pe+1], bitVectorRead(Ecp, pe+1))) { | |
| 	    /* Add clause to inherited list. */ | |
| 	    newclause = ALLOC(TlClause,1); | |
| 	    if (newclause == NULL) goto cleanup; | |
| 	    newclause->v1 = Tcv[pt]; | |
| 	    newclause->v2 = Tcv[pt+1]; | |
| 	    newclause->p1 = bitVectorRead(Tcp, pt); | |
| 	    newclause->p2 = bitVectorRead(Tcp, pt+1); | |
| 	    newclause->next = iclauses; | |
| 	    iclauses = newclause; | |
| 	    pt += 2; pe += 2; cv++; | |
| 	} else if (beforep(Tcv[pt], bitVectorRead(Tcp, pt), | |
| 		   Tcv[pt+1], bitVectorRead(Tcp, pt+1), | |
| 		   Ecv[pe], bitVectorRead(Ecp, pe), | |
| 		   Ecv[pe+1], bitVectorRead(Ecp, pe+1))) { | |
| 	    if (oneliteralp(Tcv[pt+1])) { | |
| 		/* Add this one-literal clause to the T set. */ | |
| 		newclause = ALLOC(TlClause,1); | |
| 		if (newclause == NULL) goto cleanup; | |
| 		newclause->v1 = Tcv[pt]; | |
| 		newclause->v2 = CUDD_MAXINDEX; | |
| 		newclause->p1 = bitVectorRead(Tcp, pt); | |
| 		newclause->p2 = 1; | |
| 		newclause->next = tclauses; | |
| 		tclauses = newclause; | |
| 		bitVectorSet(Tolv, Tcv[pt], 1); | |
| 		bitVectorSet(Tolp, Tcv[pt], bitVectorRead(Tcp, pt)); | |
| 	    } else { | |
| 		if (impliedp(Tcv[pt], bitVectorRead(Tcp, pt), | |
| 			     Tcv[pt+1], bitVectorRead(Tcp, pt+1), | |
| 			     Eolv, Eolp)) { | |
| 		    /* Add clause to inherited list. */ | |
| 		    newclause = ALLOC(TlClause,1); | |
| 		    if (newclause == NULL) goto cleanup; | |
| 		    newclause->v1 = Tcv[pt]; | |
| 		    newclause->v2 = Tcv[pt+1]; | |
| 		    newclause->p1 = bitVectorRead(Tcp, pt); | |
| 		    newclause->p2 = bitVectorRead(Tcp, pt+1); | |
| 		    newclause->next = iclauses; | |
| 		    iclauses = newclause; | |
| 		    cv++; | |
| 		} | |
| 	    } | |
| 	    pt += 2; | |
| 	} else { /* !beforep() */ | |
| 	    if (oneliteralp(Ecv[pe+1])) { | |
| 		/* Add this one-literal clause to the E set. */ | |
| 		newclause = ALLOC(TlClause,1); | |
| 		if (newclause == NULL) goto cleanup; | |
| 		newclause->v1 = Ecv[pe]; | |
| 		newclause->v2 = CUDD_MAXINDEX; | |
| 		newclause->p1 = bitVectorRead(Ecp, pe); | |
| 		newclause->p2 = 1; | |
| 		newclause->next = eclauses; | |
| 		eclauses = newclause; | |
| 		bitVectorSet(Eolv, Ecv[pe], 1); | |
| 		bitVectorSet(Eolp, Ecv[pe], bitVectorRead(Ecp, pe)); | |
| 	    } else { | |
| 		if (impliedp(Ecv[pe], bitVectorRead(Ecp, pe), | |
| 			     Ecv[pe+1], bitVectorRead(Ecp, pe+1), | |
| 			     Tolv, Tolp)) { | |
| 		    /* Add clause to inherited list. */ | |
| 		    newclause = ALLOC(TlClause,1); | |
| 		    if (newclause == NULL) goto cleanup; | |
| 		    newclause->v1 = Ecv[pe]; | |
| 		    newclause->v2 = Ecv[pe+1]; | |
| 		    newclause->p1 = bitVectorRead(Ecp, pe); | |
| 		    newclause->p2 = bitVectorRead(Ecp, pe+1); | |
| 		    newclause->next = iclauses; | |
| 		    iclauses = newclause; | |
| 		    cv++; | |
| 		} | |
| 	    } | |
| 	    pe += 2; | |
| 	} | |
|     } | |
| 
 | |
|     /* Add one-literal clauses for the label variable to the front of | |
|     ** the two lists. */ | |
|     newclause = ALLOC(TlClause,1); | |
|     if (newclause == NULL) goto cleanup; | |
|     newclause->v1 = label; | |
|     newclause->v2 = CUDD_MAXINDEX; | |
|     newclause->p1 = 0; | |
|     newclause->p2 = 1; | |
|     newclause->next = tclauses; | |
|     tclauses = newclause; | |
|     newclause = ALLOC(TlClause,1); | |
|     if (newclause == NULL) goto cleanup; | |
|     newclause->v1 = label; | |
|     newclause->v2 = CUDD_MAXINDEX; | |
|     newclause->p1 = 1; | |
|     newclause->p2 = 1; | |
|     newclause->next = eclauses; | |
|     eclauses = newclause; | |
| 
 | |
|     /* Produce the non-inherited clauses.  We preserve the "reverse" | |
|     ** order of the two input lists by appending to the end of the | |
|     ** list.  In this way, iclauses and nclauses are consistent. */ | |
|     while (tclauses != NULL && eclauses != NULL) { | |
| 	if (beforep(eclauses->v1, eclauses->p1, eclauses->v2, eclauses->p2, | |
| 		    tclauses->v1, tclauses->p1, tclauses->v2, tclauses->p2)) { | |
| 	    TlClause *nextclause = tclauses->next; | |
| 	    TlClause *otherclauses = eclauses; | |
| 	    while (otherclauses != NULL) { | |
| 		if (tclauses->v1 != otherclauses->v1) { | |
| 		    newclause = ALLOC(TlClause,1); | |
| 		    if (newclause == NULL) goto cleanup; | |
| 		    newclause->v1 = tclauses->v1; | |
| 		    newclause->v2 = otherclauses->v1; | |
| 		    newclause->p1 = tclauses->p1; | |
| 		    newclause->p2 = otherclauses->p1; | |
| 		    newclause->next = NULL; | |
| 		    if (nclauses == NULL) { | |
| 			nclauses = newclause; | |
| 			lnclause = newclause; | |
| 		    } else { | |
| 			lnclause->next = newclause; | |
| 			lnclause = newclause; | |
| 		    } | |
| 		    cv++; | |
| 		} | |
| 		otherclauses = otherclauses->next; | |
| 	    } | |
| 	    FREE(tclauses); | |
| 	    tclauses = nextclause; | |
| 	} else { | |
| 	    TlClause *nextclause = eclauses->next; | |
| 	    TlClause *otherclauses = tclauses; | |
| 	    while (otherclauses != NULL) { | |
| 		if (eclauses->v1 != otherclauses->v1) { | |
| 		    newclause = ALLOC(TlClause,1); | |
| 		    if (newclause == NULL) goto cleanup; | |
| 		    newclause->v1 = eclauses->v1; | |
| 		    newclause->v2 = otherclauses->v1; | |
| 		    newclause->p1 = eclauses->p1; | |
| 		    newclause->p2 = otherclauses->p1; | |
| 		    newclause->next = NULL; | |
| 		    if (nclauses == NULL) { | |
| 			nclauses = newclause; | |
| 			lnclause = newclause; | |
| 		    } else { | |
| 			lnclause->next = newclause; | |
| 			lnclause = newclause; | |
| 		    } | |
| 		    cv++; | |
| 		} | |
| 		otherclauses = otherclauses->next; | |
| 	    } | |
| 	    FREE(eclauses); | |
| 	    eclauses = nextclause; | |
| 	} | |
|     } | |
|     while (tclauses != NULL) { | |
| 	TlClause *nextclause = tclauses->next; | |
| 	FREE(tclauses); | |
| 	tclauses = nextclause; | |
|     } | |
|     while (eclauses != NULL) { | |
| 	TlClause *nextclause = eclauses->next; | |
| 	FREE(eclauses); | |
| 	eclauses = nextclause; | |
|     } | |
| 
 | |
|     /* Merge inherited and non-inherited clauses.  Now that we know the | |
|     ** total number, we allocate the arrays, and we fill them bottom-up | |
|     ** to restore the proper ordering. */ | |
|     Vcv = ALLOC(DdHalfWord, 2*(cv+1)); | |
|     if (Vcv == NULL) goto cleanup; | |
|     if (cv > 0) { | |
| 	Vcp = bitVectorAlloc(2*cv); | |
| 	if (Vcp == NULL) goto cleanup; | |
|     } else { | |
| 	Vcp = NULL; | |
|     } | |
|     res->vars = Vcv; | |
|     res->phases = Vcp; | |
|     /* Add sentinel. */ | |
|     Vcv[2*cv] = 0; | |
|     Vcv[2*cv+1] = 0; | |
|     while (iclauses != NULL || nclauses != NULL) { | |
| 	TlClause *nextclause; | |
| 	cv--; | |
| 	if (nclauses == NULL || (iclauses != NULL && | |
| 	    beforep(nclauses->v1, nclauses->p1, nclauses->v2, nclauses->p2, | |
| 		    iclauses->v1, iclauses->p1, iclauses->v2, iclauses->p2))) { | |
| 	    Vcv[2*cv] = iclauses->v1; | |
| 	    Vcv[2*cv+1] = iclauses->v2; | |
| 	    bitVectorSet(Vcp, 2*cv, iclauses->p1); | |
| 	    bitVectorSet(Vcp, 2*cv+1, iclauses->p2); | |
| 	    nextclause = iclauses->next; | |
| 	    FREE(iclauses); | |
| 	    iclauses = nextclause; | |
| 	} else { | |
| 	    Vcv[2*cv] = nclauses->v1; | |
| 	    Vcv[2*cv+1] = nclauses->v2; | |
| 	    bitVectorSet(Vcp, 2*cv, nclauses->p1); | |
| 	    bitVectorSet(Vcp, 2*cv+1, nclauses->p2); | |
| 	    nextclause = nclauses->next; | |
| 	    FREE(nclauses); | |
| 	    nclauses = nextclause; | |
| 	} | |
|     } | |
|     assert(cv == 0); | |
| 
 | |
|     return(res); | |
| 
 | |
|  cleanup: | |
|     if (res != NULL) Cudd_tlcInfoFree(res); | |
|     while (iclauses != NULL) { | |
| 	TlClause *nextclause = iclauses->next; | |
| 	FREE(iclauses); | |
| 	iclauses = nextclause; | |
|     } | |
|     while (nclauses != NULL) { | |
| 	TlClause *nextclause = nclauses->next; | |
| 	FREE(nclauses); | |
| 	nclauses = nextclause; | |
|     } | |
|     while (tclauses != NULL) { | |
| 	TlClause *nextclause = tclauses->next; | |
| 	FREE(tclauses); | |
| 	tclauses = nextclause; | |
|     } | |
|     while (eclauses != NULL) { | |
| 	TlClause *nextclause = eclauses->next; | |
| 	FREE(eclauses); | |
| 	eclauses = nextclause; | |
|     } | |
| 
 | |
|     return(NULL); | |
| 
 | |
| } /* end of computeClauses */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Computes the two-literal clauses for a node. | |
|  | |
|   @details Computes the two-literal clauses for a node with a zero | |
|   child, given the clauses for its other child and the label of the | |
|   node. | |
|  | |
|   @return a pointer to a TclInfo structure if successful; NULL | |
|   otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see computeClauses | |
|  | |
| */ | |
| static DdTlcInfo * | |
| computeClausesWithUniverse( | |
|   DdTlcInfo *Cres /* list of clauses for child */, | |
|   DdHalfWord label /* variable labeling the current node */, | |
|   short phase /* 0 if E child is zero; 1 if T child is zero */) | |
| { | |
|     DdHalfWord *Ccv = Cres->vars; /* variables of clauses for child */ | |
|     BitVector *Ccp = Cres->phases; /* phases of clauses for child */ | |
|     DdHalfWord *Vcv = NULL; /* pointer to the variables of the clauses for v */ | |
|     BitVector *Vcp = NULL; /* pointer to the phases of the clauses for v */ | |
|     DdTlcInfo *res = NULL; /* the set of clauses to be returned */ | |
|     int i; | |
| 
 | |
|     /* Initialize result. */ | |
|     res = tlcInfoAlloc(); | |
|     if (res == NULL) goto cleanup; | |
|     /* Count entries for new list and allocate accordingly. */ | |
|     for (i = 0; !sentinelp(Ccv[i], Ccv[i+1]); i += 2); | |
|     /* At this point, i is twice the number of clauses in the child's | |
|     ** list.  We need four more entries for this node: 2 for the one-literal | |
|     ** clause for the label, and 2 for the sentinel. */ | |
|     Vcv = ALLOC(DdHalfWord,i+4); | |
|     if (Vcv == NULL) goto cleanup; | |
|     Vcp = bitVectorAlloc(i+4); | |
|     if (Vcp == NULL) goto cleanup; | |
|     res->vars = Vcv; | |
|     res->phases = Vcp; | |
|     /* Copy old list into new. */ | |
|     for (i = 0; !sentinelp(Ccv[i], Ccv[i+1]); i += 2) { | |
| 	Vcv[i] = Ccv[i]; | |
| 	Vcv[i+1] = Ccv[i+1]; | |
| 	bitVectorSet(Vcp, i, bitVectorRead(Ccp, i)); | |
| 	bitVectorSet(Vcp, i+1, bitVectorRead(Ccp, i+1)); | |
|     } | |
|     /* Add clause corresponding to label. */ | |
|     Vcv[i] = label; | |
|     bitVectorSet(Vcp, i, phase); | |
|     i++; | |
|     Vcv[i] = CUDD_MAXINDEX; | |
|     bitVectorSet(Vcp, i, 1); | |
|     i++; | |
|     /* Add sentinel. */ | |
|     Vcv[i] = 0; | |
|     Vcv[i+1] = 0; | |
|     bitVectorSet(Vcp, i, 0); | |
|     bitVectorSet(Vcp, i+1, 0); | |
| 
 | |
|     return(res); | |
| 
 | |
|  cleanup: | |
|     /* Vcp is guaranteed to be NULL here.  Hence, we do not try to free it. */ | |
|     if (Vcv != NULL) FREE(Vcv); | |
|     if (res != NULL) Cudd_tlcInfoFree(res); | |
| 
 | |
|     return(NULL); | |
| 
 | |
| } /* end of computeClausesWithUniverse */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns an enpty set of clauses. | |
|  | |
|   @details No bit vector for the phases is allocated. | |
|  | |
|   @return a pointer to an empty set of clauses if successful; NULL | |
|   otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static DdTlcInfo * | |
| emptyClauseSet(void) | |
| { | |
|     DdTlcInfo *eset; | |
| 
 | |
|     eset = ALLOC(DdTlcInfo,1); | |
|     if (eset == NULL) return(NULL); | |
|     eset->vars = ALLOC(DdHalfWord,2); | |
|     if (eset->vars == NULL) { | |
| 	FREE(eset); | |
| 	return(NULL); | |
|     } | |
|     /* Sentinel */ | |
|     eset->vars[0] = 0; | |
|     eset->vars[1] = 0; | |
|     eset->phases = NULL; /* does not matter */ | |
|     eset->cnt = 0; | |
|     return(eset); | |
| 
 | |
| } /* end of emptyClauseSet */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns true iff the argument is the sentinel clause. | |
|  | |
|   @details A sentinel clause has both variables equal to 0. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| sentinelp( | |
|   DdHalfWord var1, | |
|   DdHalfWord var2) | |
| { | |
|     return(var1 == 0 && var2 == 0); | |
| 
 | |
| } /* end of sentinelp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns true iff the two arguments are identical clauses. | |
|  | |
|   @details Since literals are sorted, we only need to compare literals | |
|   in the same position. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see beforep | |
|  | |
| */ | |
| static int | |
| equalp( | |
|   DdHalfWord var1a, | |
|   short phase1a, | |
|   DdHalfWord var1b, | |
|   short phase1b, | |
|   DdHalfWord var2a, | |
|   short phase2a, | |
|   DdHalfWord var2b, | |
|   short phase2b) | |
| { | |
|     return(var1a == var2a && phase1a == phase2a && | |
| 	   var1b == var2b && phase1b == phase2b); | |
| 
 | |
| } /* end of equalp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns true iff the first argument precedes the second in | |
|   the clause order. | |
|  | |
|   @details A clause precedes another if its first lieral | |
|   precedes the first literal of the other, or if the first literals | |
|   are the same, and its second literal precedes the second literal of | |
|   the other clause.  A literal precedes another if it has a higher | |
|   index, of if it has the same index, but it has lower phase.  Phase 0 | |
|   is the positive phase, and it is lower than Phase 1 (negative | |
|   phase). | |
|  | |
|   @sideeffect None | |
|  | |
|   @see equalp | |
|  | |
| */ | |
| static int | |
| beforep( | |
|   DdHalfWord var1a, | |
|   short phase1a, | |
|   DdHalfWord var1b, | |
|   short phase1b, | |
|   DdHalfWord var2a, | |
|   short phase2a, | |
|   DdHalfWord var2b, | |
|   short phase2b) | |
| { | |
|     return(var1a > var2a || (var1a == var2a && | |
| 	   (phase1a < phase2a || (phase1a == phase2a && | |
| 	    (var1b > var2b || (var1b == var2b && phase1b < phase2b)))))); | |
| 
 | |
| } /* end of beforep */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns true iff the argument is a one-literal clause. | |
|  | |
|   @details A one-litaral clause has the constant FALSE as second | |
|   literal.  Since the constant TRUE is never used, it is sufficient to | |
|   test for a constant. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| oneliteralp( | |
|   DdHalfWord var) | |
| { | |
|     return(var == CUDD_MAXINDEX); | |
| 
 | |
| } /* end of oneliteralp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns true iff either literal of a clause is in a set of | |
|   literals. | |
|  | |
|   @details The first four arguments specify the clause.  The remaining | |
|   two arguments specify the literal set. | |
|  | |
|   @sideeffect None | |
|  | |
| */ | |
| static int | |
| impliedp( | |
|   DdHalfWord var1, | |
|   short phase1, | |
|   DdHalfWord var2, | |
|   short phase2, | |
|   BitVector *olv, | |
|   BitVector *olp) | |
| { | |
|     return((bitVectorRead(olv, var1) && | |
| 	    bitVectorRead(olp, var1) == phase1) || | |
| 	   (bitVectorRead(olv, var2) && | |
| 	    bitVectorRead(olp, var2) == phase2)); | |
| 
 | |
| } /* end of impliedp */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Allocates a bit vector. | |
|  | |
|   @details The parameter size gives the number of bits.  This | |
|   procedure allocates enough words to hold the specified number of | |
|   bits. | |
|  | |
|   @return a pointer to the allocated vector if successful; NULL | |
|   otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bitVectorClear bitVectorFree | |
|  | |
| */ | |
| static BitVector * | |
| bitVectorAlloc( | |
|   int size) | |
| { | |
|     int allocSize; | |
|     BitVector *vector; | |
| 
 | |
|     /* Find out how many words we need. | |
|     ** There are sizeof(ptruint) * 8 bits in a ptruint. | |
|     ** The ceiling of the ratio of two integers m and n is given | |
|     ** by ((n-1)/m)+1.  Putting all this together, we get... */ | |
|     allocSize = ((size - 1) / (sizeof(BitVector) * 8)) + 1; | |
|     vector = ALLOC(BitVector, allocSize); | |
|     if (vector == NULL) return(NULL); | |
|     /* Clear the whole array. */ | |
|     (void) memset(vector, 0, allocSize * sizeof(BitVector)); | |
|     return(vector); | |
| 
 | |
| } /* end of bitVectorAlloc */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Clears a bit vector. | |
|  | |
|   @details The parameter size gives the number of bits. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bitVectorAlloc | |
|  | |
| */ | |
| static void | |
| bitVectorClear( | |
|   BitVector *vector, | |
|   int size) | |
| { | |
|     int allocSize; | |
| 
 | |
|     /* Find out how many words we need. | |
|     ** There are sizeof(ptruint) * 8 bits in a ptruint. | |
|     ** The ceiling of the ratio of two integers m and n is given | |
|     ** by ((n-1)/m)+1.  Putting all this together, we get... */ | |
|     allocSize = ((size - 1) / (sizeof(BitVector) * 8)) + 1; | |
|     /* Clear the whole array. */ | |
|     (void) memset(vector, 0, allocSize * sizeof(BitVector)); | |
|     return; | |
| 
 | |
| } /* end of bitVectorClear */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Frees a bit vector. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bitVectorAlloc | |
|  | |
| */ | |
| static void | |
| bitVectorFree( | |
|   BitVector *vector) | |
| { | |
|     FREE(vector); | |
| 
 | |
| } /* end of bitVectorFree */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Returns the i-th entry of a bit vector. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bitVectorSet | |
|  | |
| */ | |
| static short | |
| bitVectorRead( | |
|   BitVector *vector, | |
|   int i) | |
| { | |
|     int word, bit; | |
|     short result; | |
| 
 | |
|     if (vector == NULL) return((short) 0); | |
| 
 | |
|     word = i >> LOGBPL; | |
|     bit = i & (BPL - 1); | |
|     result = (short) ((vector[word] >> bit) & (ptruint) 1); | |
|     return(result); | |
| 
 | |
| } /* end of bitVectorRead */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Sets the i-th entry of a bit vector to a value. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see bitVectorRead | |
|  | |
| */ | |
| static void | |
| bitVectorSet( | |
|   BitVector * vector, | |
|   int i, | |
|   short val) | |
| { | |
|     int word, bit; | |
| 
 | |
|     word = i >> LOGBPL; | |
|     bit = i & (BPL - 1); | |
|     vector[word] &= ~((ptruint) 1 << bit); | |
|     vector[word] |= (((ptruint) val) << bit); | |
| 
 | |
| } /* end of bitVectorSet */ | |
| 
 | |
| 
 | |
| /** | |
|   @brief Allocates a DdTlcInfo Structure. | |
|  | |
|   @return a pointer to a DdTlcInfo Structure if successful; NULL | |
|   otherwise. | |
|  | |
|   @sideeffect None | |
|  | |
|   @see Cudd_tlcInfoFree | |
|  | |
| */ | |
| static DdTlcInfo * | |
| tlcInfoAlloc(void) | |
| { | |
|     DdTlcInfo *res = ALLOC(DdTlcInfo,1); | |
|     if (res == NULL) return(NULL); | |
|     res->vars = NULL; | |
|     res->phases = NULL; | |
|     res->cnt = 0; | |
|     return(res); | |
| 
 | |
| } /* end of tlcInfoAlloc */
 |