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.
		
		
		
		
		
			
		
			
				
					
					
						
							558 lines
						
					
					
						
							16 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							558 lines
						
					
					
						
							16 KiB
						
					
					
				| /**CFile*********************************************************************** | |
|  | |
|   FileName    [cuddClip.c] | |
|  | |
|   PackageName [cudd] | |
|  | |
|   Synopsis    [Clipping functions.] | |
|  | |
|   Description [External procedures included in this module: | |
| 		<ul> | |
| 		<li> Cudd_bddClippingAnd() | |
| 		<li> Cudd_bddClippingAndAbstract() | |
| 		</ul> | |
|        Internal procedures included in this module: | |
| 		<ul> | |
| 		<li> cuddBddClippingAnd() | |
| 		<li> cuddBddClippingAndAbstract() | |
| 		</ul> | |
|        Static procedures included in this module: | |
| 		<ul> | |
| 		<li> cuddBddClippingAndRecur() | |
| 		<li> cuddBddClipAndAbsRecur() | |
| 		</ul> | |
|  | |
|   SeeAlso     [] | |
|  | |
|   Author      [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                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #ifndef lint | |
| static char rcsid[] DD_UNUSED = "$Id: cuddClip.c,v 1.9 2012/02/05 01:07:18 fabio Exp $"; | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**AutomaticStart*************************************************************/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static DdNode * cuddBddClippingAndRecur (DdManager *manager, DdNode *f, DdNode *g, int distance, int direction); | |
| static DdNode * cuddBddClipAndAbsRecur (DdManager *manager, DdNode *f, DdNode *g, DdNode *cube, int distance, int direction); | |
| 
 | |
| /**AutomaticEnd***************************************************************/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Approximates the conjunction of two BDDs f and g.] | |
|  | |
|   Description [Approximates the conjunction of two BDDs f and g. Returns a | |
|   pointer to the resulting BDD if successful; NULL if the intermediate | |
|   result blows up.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddAnd] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_bddClippingAnd( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* first conjunct */, | |
|   DdNode * g /* second conjunct */, | |
|   int  maxDepth /* maximum recursion depth */, | |
|   int  direction /* under (0) or over (1) approximation */) | |
| { | |
|     DdNode *res; | |
| 
 | |
|     do { | |
| 	dd->reordered = 0; | |
| 	res = cuddBddClippingAnd(dd,f,g,maxDepth,direction); | |
|     } while (dd->reordered == 1); | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_bddClippingAnd */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Approximates the conjunction of two BDDs f and g and | |
|   simultaneously abstracts the variables in cube.] | |
|  | |
|   Description [Approximates the conjunction of two BDDs f and g and | |
|   simultaneously abstracts the variables in cube. The variables are | |
|   existentially abstracted. Returns a pointer to the resulting BDD if | |
|   successful; NULL if the intermediate result blows up.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddAndAbstract Cudd_bddClippingAnd] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_bddClippingAndAbstract( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* first conjunct */, | |
|   DdNode * g /* second conjunct */, | |
|   DdNode * cube /* cube of variables to be abstracted */, | |
|   int  maxDepth /* maximum recursion depth */, | |
|   int  direction /* under (0) or over (1) approximation */) | |
| { | |
|     DdNode *res; | |
| 
 | |
|     do { | |
| 	dd->reordered = 0; | |
| 	res = cuddBddClippingAndAbstract(dd,f,g,cube,maxDepth,direction); | |
|     } while (dd->reordered == 1); | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_bddClippingAndAbstract */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Approximates the conjunction of two BDDs f and g.] | |
|  | |
|   Description [Approximates the conjunction of two BDDs f and g. Returns a | |
|   pointer to the resulting BDD if successful; NULL if the intermediate | |
|   result blows up.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddClippingAnd] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| cuddBddClippingAnd( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* first conjunct */, | |
|   DdNode * g /* second conjunct */, | |
|   int  maxDepth /* maximum recursion depth */, | |
|   int  direction /* under (0) or over (1) approximation */) | |
| { | |
|     DdNode *res; | |
| 
 | |
|     res = cuddBddClippingAndRecur(dd,f,g,maxDepth,direction); | |
| 
 | |
|     return(res); | |
| 
 | |
| } /* end of cuddBddClippingAnd */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Approximates the conjunction of two BDDs f and g and | |
|   simultaneously abstracts the variables in cube.] | |
|  | |
|   Description [Approximates the conjunction of two BDDs f and g and | |
|   simultaneously abstracts the variables in cube. Returns a | |
|   pointer to the resulting BDD if successful; NULL if the intermediate | |
|   result blows up.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddClippingAndAbstract] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| cuddBddClippingAndAbstract( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* first conjunct */, | |
|   DdNode * g /* second conjunct */, | |
|   DdNode * cube /* cube of variables to be abstracted */, | |
|   int  maxDepth /* maximum recursion depth */, | |
|   int  direction /* under (0) or over (1) approximation */) | |
| { | |
|     DdNode *res; | |
| 
 | |
|     res = cuddBddClipAndAbsRecur(dd,f,g,cube,maxDepth,direction); | |
| 
 | |
|     return(res); | |
| 
 | |
| } /* end of cuddBddClippingAndAbstract */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Implements the recursive step of Cudd_bddClippingAnd.] | |
|  | |
|   Description [Implements the recursive step of Cudd_bddClippingAnd by taking | |
|   the conjunction of two BDDs.  Returns a pointer to the result is | |
|   successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [cuddBddClippingAnd] | |
|  | |
| ******************************************************************************/ | |
| static DdNode * | |
| cuddBddClippingAndRecur( | |
|   DdManager * manager, | |
|   DdNode * f, | |
|   DdNode * g, | |
|   int  distance, | |
|   int  direction) | |
| { | |
|     DdNode *F, *ft, *fe, *G, *gt, *ge; | |
|     DdNode *one, *zero, *r, *t, *e; | |
|     unsigned int topf, topg, index; | |
|     DD_CTFP cacheOp; | |
| 
 | |
|     statLine(manager); | |
|     one = DD_ONE(manager); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /* Terminal cases. */ | |
|     if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); | |
|     if (f == g || g == one) return(f); | |
|     if (f == one) return(g); | |
|     if (distance == 0) { | |
| 	/* One last attempt at returning the right result. We sort of | |
| 	** cheat by calling Cudd_bddLeq. */ | |
| 	if (Cudd_bddLeq(manager,f,g)) return(f); | |
| 	if (Cudd_bddLeq(manager,g,f)) return(g); | |
| 	if (direction == 1) { | |
| 	    if (Cudd_bddLeq(manager,f,Cudd_Not(g)) || | |
| 		Cudd_bddLeq(manager,g,Cudd_Not(f))) return(zero); | |
| 	} | |
| 	return(Cudd_NotCond(one,(direction == 0))); | |
|     } | |
| 
 | |
|     /* At this point f and g are not constant. */ | |
|     distance--; | |
| 
 | |
|     /* Check cache. Try to increase cache efficiency by sorting the | |
|     ** pointers. */ | |
|     if (f > g) { | |
| 	DdNode *tmp = f; | |
| 	f = g; g = tmp; | |
|     } | |
|     F = Cudd_Regular(f); | |
|     G = Cudd_Regular(g); | |
|     cacheOp = (DD_CTFP) | |
| 	(direction ? Cudd_bddClippingAnd : cuddBddClippingAnd); | |
|     if (F->ref != 1 || G->ref != 1) { | |
| 	r = cuddCacheLookup2(manager, cacheOp, f, g); | |
| 	if (r != NULL) return(r); | |
|     } | |
| 
 | |
|     /* Here we can skip the use of cuddI, because the operands are known | |
|     ** to be non-constant. | |
|     */ | |
|     topf = manager->perm[F->index]; | |
|     topg = manager->perm[G->index]; | |
| 
 | |
|     /* Compute cofactors. */ | |
|     if (topf <= topg) { | |
| 	index = F->index; | |
| 	ft = cuddT(F); | |
| 	fe = cuddE(F); | |
| 	if (Cudd_IsComplement(f)) { | |
| 	    ft = Cudd_Not(ft); | |
| 	    fe = Cudd_Not(fe); | |
| 	} | |
|     } else { | |
| 	index = G->index; | |
| 	ft = fe = f; | |
|     } | |
| 
 | |
|     if (topg <= topf) { | |
| 	gt = cuddT(G); | |
| 	ge = cuddE(G); | |
| 	if (Cudd_IsComplement(g)) { | |
| 	    gt = Cudd_Not(gt); | |
| 	    ge = Cudd_Not(ge); | |
| 	} | |
|     } else { | |
| 	gt = ge = g; | |
|     } | |
| 
 | |
|     t = cuddBddClippingAndRecur(manager, ft, gt, distance, direction); | |
|     if (t == NULL) return(NULL); | |
|     cuddRef(t); | |
|     e = cuddBddClippingAndRecur(manager, fe, ge, distance, direction); | |
|     if (e == NULL) { | |
| 	Cudd_RecursiveDeref(manager, t); | |
| 	return(NULL); | |
|     } | |
|     cuddRef(e); | |
| 
 | |
|     if (t == e) { | |
| 	r = t; | |
|     } else { | |
| 	if (Cudd_IsComplement(t)) { | |
| 	    r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); | |
| 	    if (r == NULL) { | |
| 		Cudd_RecursiveDeref(manager, t); | |
| 		Cudd_RecursiveDeref(manager, e); | |
| 		return(NULL); | |
| 	    } | |
| 	    r = Cudd_Not(r); | |
| 	} else { | |
| 	    r = cuddUniqueInter(manager,(int)index,t,e); | |
| 	    if (r == NULL) { | |
| 		Cudd_RecursiveDeref(manager, t); | |
| 		Cudd_RecursiveDeref(manager, e); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
|     } | |
|     cuddDeref(e); | |
|     cuddDeref(t); | |
|     if (F->ref != 1 || G->ref != 1) | |
| 	cuddCacheInsert2(manager, cacheOp, f, g, r); | |
|     return(r); | |
| 
 | |
| } /* end of cuddBddClippingAndRecur */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Approximates the AND of two BDDs and simultaneously abstracts the | |
|   variables in cube.] | |
|  | |
|   Description [Approximates the AND of two BDDs and simultaneously | |
|   abstracts the variables in cube. The variables are existentially | |
|   abstracted.  Returns a pointer to the result is successful; NULL | |
|   otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddClippingAndAbstract] | |
|  | |
| ******************************************************************************/ | |
| static DdNode * | |
| cuddBddClipAndAbsRecur( | |
|   DdManager * manager, | |
|   DdNode * f, | |
|   DdNode * g, | |
|   DdNode * cube, | |
|   int  distance, | |
|   int  direction) | |
| { | |
|     DdNode *F, *ft, *fe, *G, *gt, *ge; | |
|     DdNode *one, *zero, *r, *t, *e, *Cube; | |
|     unsigned int topf, topg, topcube, top, index; | |
|     ptruint cacheTag; | |
| 
 | |
|     statLine(manager); | |
|     one = DD_ONE(manager); | |
|     zero = Cudd_Not(one); | |
| 
 | |
|     /* Terminal cases. */ | |
|     if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); | |
|     if (f == one && g == one)	return(one); | |
|     if (cube == one) { | |
| 	return(cuddBddClippingAndRecur(manager, f, g, distance, direction)); | |
|     } | |
|     if (f == one || f == g) { | |
| 	return (cuddBddExistAbstractRecur(manager, g, cube)); | |
|     } | |
|     if (g == one) { | |
| 	return (cuddBddExistAbstractRecur(manager, f, cube)); | |
|     } | |
|     if (distance == 0) return(Cudd_NotCond(one,(direction == 0))); | |
| 
 | |
|     /* At this point f, g, and cube are not constant. */ | |
|     distance--; | |
| 
 | |
|     /* Check cache. */ | |
|     if (f > g) { /* Try to increase cache efficiency. */ | |
| 	DdNode *tmp = f; | |
| 	f = g; g = tmp; | |
|     } | |
|     F = Cudd_Regular(f); | |
|     G = Cudd_Regular(g); | |
|     cacheTag = direction ? DD_BDD_CLIPPING_AND_ABSTRACT_UP_TAG : | |
| 	DD_BDD_CLIPPING_AND_ABSTRACT_DOWN_TAG; | |
|     if (F->ref != 1 || G->ref != 1) { | |
| 	r = cuddCacheLookup(manager, cacheTag, | |
| 			    f, g, cube); | |
| 	if (r != NULL) { | |
| 	    return(r); | |
| 	} | |
|     } | |
| 
 | |
|     /* Here we can skip the use of cuddI, because the operands are known | |
|     ** to be non-constant. | |
|     */ | |
|     topf = manager->perm[F->index]; | |
|     topg = manager->perm[G->index]; | |
|     top = ddMin(topf, topg); | |
|     topcube = manager->perm[cube->index]; | |
| 
 | |
|     if (topcube < top) { | |
| 	return(cuddBddClipAndAbsRecur(manager, f, g, cuddT(cube), | |
| 				      distance, direction)); | |
|     } | |
|     /* Now, topcube >= top. */ | |
| 
 | |
|     if (topf == top) { | |
| 	index = F->index; | |
| 	ft = cuddT(F); | |
| 	fe = cuddE(F); | |
| 	if (Cudd_IsComplement(f)) { | |
| 	    ft = Cudd_Not(ft); | |
| 	    fe = Cudd_Not(fe); | |
| 	} | |
|     } else { | |
| 	index = G->index; | |
| 	ft = fe = f; | |
|     } | |
| 
 | |
|     if (topg == top) { | |
| 	gt = cuddT(G); | |
| 	ge = cuddE(G); | |
| 	if (Cudd_IsComplement(g)) { | |
| 	    gt = Cudd_Not(gt); | |
| 	    ge = Cudd_Not(ge); | |
| 	} | |
|     } else { | |
| 	gt = ge = g; | |
|     } | |
| 
 | |
|     if (topcube == top) { | |
| 	Cube = cuddT(cube); | |
|     } else { | |
| 	Cube = cube; | |
|     } | |
| 
 | |
|     t = cuddBddClipAndAbsRecur(manager, ft, gt, Cube, distance, direction); | |
|     if (t == NULL) return(NULL); | |
| 
 | |
|     /* Special case: 1 OR anything = 1. Hence, no need to compute | |
|     ** the else branch if t is 1. | |
|     */ | |
|     if (t == one && topcube == top) { | |
| 	if (F->ref != 1 || G->ref != 1) | |
| 	    cuddCacheInsert(manager, cacheTag, f, g, cube, one); | |
| 	return(one); | |
|     } | |
|     cuddRef(t); | |
| 
 | |
|     e = cuddBddClipAndAbsRecur(manager, fe, ge, Cube, distance, direction); | |
|     if (e == NULL) { | |
| 	Cudd_RecursiveDeref(manager, t); | |
| 	return(NULL); | |
|     } | |
|     cuddRef(e); | |
| 
 | |
|     if (topcube == top) {	/* abstract */ | |
| 	r = cuddBddClippingAndRecur(manager, Cudd_Not(t), Cudd_Not(e), | |
| 				    distance, (direction == 0)); | |
| 	if (r == NULL) { | |
| 	    Cudd_RecursiveDeref(manager, t); | |
| 	    Cudd_RecursiveDeref(manager, e); | |
| 	    return(NULL); | |
| 	} | |
| 	r = Cudd_Not(r); | |
| 	cuddRef(r); | |
| 	Cudd_RecursiveDeref(manager, t); | |
| 	Cudd_RecursiveDeref(manager, e); | |
| 	cuddDeref(r); | |
|     } else if (t == e) { | |
| 	r = t; | |
| 	cuddDeref(t); | |
| 	cuddDeref(e); | |
|     } else { | |
| 	if (Cudd_IsComplement(t)) { | |
| 	    r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); | |
| 	    if (r == NULL) { | |
| 		Cudd_RecursiveDeref(manager, t); | |
| 		Cudd_RecursiveDeref(manager, e); | |
| 		return(NULL); | |
| 	    } | |
| 	    r = Cudd_Not(r); | |
| 	} else { | |
| 	    r = cuddUniqueInter(manager,(int)index,t,e); | |
| 	    if (r == NULL) { | |
| 		Cudd_RecursiveDeref(manager, t); | |
| 		Cudd_RecursiveDeref(manager, e); | |
| 		return(NULL); | |
| 	    } | |
| 	} | |
| 	cuddDeref(e); | |
| 	cuddDeref(t); | |
|     } | |
|     if (F->ref != 1 || G->ref != 1) | |
| 	cuddCacheInsert(manager, cacheTag, f, g, cube, r); | |
|     return (r); | |
| 
 | |
| } /* end of cuddBddClipAndAbsRecur */ | |
| 
 |