1 /**CFile***********************************************************************
3 FileName [cuddBddAbs.c]
7 Synopsis [Quantification functions for BDDs.]
9 Description [External procedures included in this module:
11 <li> Cudd_bddExistAbstract()
12 <li> Cudd_bddXorExistAbstract()
13 <li> Cudd_bddUnivAbstract()
14 <li> Cudd_bddBooleanDiff()
15 <li> Cudd_bddVarIsDependent()
17 Internal procedures included in this module:
19 <li> cuddBddExistAbstractRecur()
20 <li> cuddBddXorExistAbstractRecur()
21 <li> cuddBddBooleanDiffRecur()
23 Static procedures included in this module:
25 <li> bddCheckPositiveCube()
29 Author [Fabio Somenzi]
31 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
35 Redistribution and use in source and binary forms, with or without
36 modification, are permitted provided that the following conditions
39 Redistributions of source code must retain the above copyright
40 notice, this list of conditions and the following disclaimer.
42 Redistributions in binary form must reproduce the above copyright
43 notice, this list of conditions and the following disclaimer in the
44 documentation and/or other materials provided with the distribution.
46 Neither the name of the University of Colorado nor the names of its
47 contributors may be used to endorse or promote products derived from
48 this software without specific prior written permission.
50 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
53 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
54 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
55 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
56 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
58 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
60 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 POSSIBILITY OF SUCH DAMAGE.]
63 ******************************************************************************/
69 /*---------------------------------------------------------------------------*/
70 /* Constant declarations */
71 /*---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------*/
75 /* Stucture declarations */
76 /*---------------------------------------------------------------------------*/
79 /*---------------------------------------------------------------------------*/
80 /* Type declarations */
81 /*---------------------------------------------------------------------------*/
84 /*---------------------------------------------------------------------------*/
85 /* Variable declarations */
86 /*---------------------------------------------------------------------------*/
89 static char rcsid
[] DD_UNUSED
= "$Id: cuddBddAbs.c,v 1.26 2004/08/13 18:04:46 fabio Exp $";
92 /*---------------------------------------------------------------------------*/
93 /* Macro declarations */
94 /*---------------------------------------------------------------------------*/
97 /**AutomaticStart*************************************************************/
99 /*---------------------------------------------------------------------------*/
100 /* Static function prototypes */
101 /*---------------------------------------------------------------------------*/
103 static int bddCheckPositiveCube (DdManager
*manager
, DdNode
*cube
);
105 /**AutomaticEnd***************************************************************/
108 /*---------------------------------------------------------------------------*/
109 /* Definition of exported functions */
110 /*---------------------------------------------------------------------------*/
113 /**Function********************************************************************
115 Synopsis [Existentially abstracts all the variables in cube from f.]
117 Description [Existentially abstracts all the variables in cube from f.
118 Returns the abstracted BDD if successful; NULL otherwise.]
122 SeeAlso [Cudd_bddUnivAbstract Cudd_addExistAbstract]
124 ******************************************************************************/
126 Cudd_bddExistAbstract(
133 if (bddCheckPositiveCube(manager
, cube
) == 0) {
134 (void) fprintf(manager
->err
,
135 "Error: Can only abstract positive cubes\n");
136 manager
->errorCode
= CUDD_INVALID_ARG
;
141 manager
->reordered
= 0;
142 res
= cuddBddExistAbstractRecur(manager
, f
, cube
);
143 } while (manager
->reordered
== 1);
147 } /* end of Cudd_bddExistAbstract */
150 /**Function********************************************************************
152 Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the
155 Description [Takes the exclusive OR of two BDDs and simultaneously abstracts
156 the variables in cube. The variables are existentially abstracted. Returns a
157 pointer to the result is successful; NULL otherwise.]
161 SeeAlso [Cudd_bddUnivAbstract Cudd_bddExistAbstract Cudd_bddAndAbstract]
163 ******************************************************************************/
165 Cudd_bddXorExistAbstract(
173 if (bddCheckPositiveCube(manager
, cube
) == 0) {
174 (void) fprintf(manager
->err
,
175 "Error: Can only abstract positive cubes\n");
176 manager
->errorCode
= CUDD_INVALID_ARG
;
181 manager
->reordered
= 0;
182 res
= cuddBddXorExistAbstractRecur(manager
, f
, g
, cube
);
183 } while (manager
->reordered
== 1);
187 } /* end of Cudd_bddXorExistAbstract */
190 /**Function********************************************************************
192 Synopsis [Universally abstracts all the variables in cube from f.]
194 Description [Universally abstracts all the variables in cube from f.
195 Returns the abstracted BDD if successful; NULL otherwise.]
199 SeeAlso [Cudd_bddExistAbstract Cudd_addUnivAbstract]
201 ******************************************************************************/
203 Cudd_bddUnivAbstract(
210 if (bddCheckPositiveCube(manager
, cube
) == 0) {
211 (void) fprintf(manager
->err
,
212 "Error: Can only abstract positive cubes\n");
213 manager
->errorCode
= CUDD_INVALID_ARG
;
218 manager
->reordered
= 0;
219 res
= cuddBddExistAbstractRecur(manager
, Cudd_Not(f
), cube
);
220 } while (manager
->reordered
== 1);
221 if (res
!= NULL
) res
= Cudd_Not(res
);
225 } /* end of Cudd_bddUnivAbstract */
228 /**Function********************************************************************
230 Synopsis [Computes the boolean difference of f with respect to x.]
232 Description [Computes the boolean difference of f with respect to the
233 variable with index x. Returns the BDD of the boolean difference if
234 successful; NULL otherwise.]
240 ******************************************************************************/
249 /* If the variable is not currently in the manager, f cannot
252 if (x
>= manager
->size
) return(Cudd_Not(DD_ONE(manager
)));
253 var
= manager
->vars
[x
];
256 manager
->reordered
= 0;
257 res
= cuddBddBooleanDiffRecur(manager
, Cudd_Regular(f
), var
);
258 } while (manager
->reordered
== 1);
262 } /* end of Cudd_bddBooleanDiff */
265 /**Function********************************************************************
267 Synopsis [Checks whether a variable is dependent on others in a
270 Description [Checks whether a variable is dependent on others in a
271 function. Returns 1 if the variable is dependent; 0 otherwise. No
272 new nodes are created.]
278 ******************************************************************************/
280 Cudd_bddVarIsDependent(
281 DdManager
*dd
, /* manager */
282 DdNode
*f
, /* function */
283 DdNode
*var
/* variable */)
285 DdNode
*F
, *res
, *zero
, *ft
, *fe
;
286 unsigned topf
, level
;
290 zero
= Cudd_Not(DD_ONE(dd
));
291 if (Cudd_IsConstant(f
)) return(f
== zero
);
293 /* From now on f is not constant. */
295 topf
= (unsigned) dd
->perm
[F
->index
];
296 level
= (unsigned) dd
->perm
[var
->index
];
298 /* Check terminal case. If topf > index of var, f does not depend on var.
299 ** Therefore, var is not dependent in f. */
304 cacheOp
= (DD_CTFP
) Cudd_bddVarIsDependent
;
305 res
= cuddCacheLookup2(dd
,cacheOp
,f
,var
);
310 /* Compute cofactors. */
311 ft
= Cudd_NotCond(cuddT(F
), f
!= F
);
312 fe
= Cudd_NotCond(cuddE(F
), f
!= F
);
315 retval
= Cudd_bddLeq(dd
,ft
,Cudd_Not(fe
));
317 retval
= Cudd_bddVarIsDependent(dd
,ft
,var
) &&
318 Cudd_bddVarIsDependent(dd
,fe
,var
);
321 cuddCacheInsert2(dd
,cacheOp
,f
,var
,Cudd_NotCond(zero
,retval
));
325 } /* Cudd_bddVarIsDependent */
328 /*---------------------------------------------------------------------------*/
329 /* Definition of internal functions */
330 /*---------------------------------------------------------------------------*/
333 /**Function********************************************************************
335 Synopsis [Performs the recursive steps of Cudd_bddExistAbstract.]
337 Description [Performs the recursive steps of Cudd_bddExistAbstract.
338 Returns the BDD obtained by abstracting the variables
339 of cube from f if successful; NULL otherwise. It is also used by
340 Cudd_bddUnivAbstract.]
344 SeeAlso [Cudd_bddExistAbstract Cudd_bddUnivAbstract]
346 ******************************************************************************/
348 cuddBddExistAbstractRecur(
353 DdNode
*F
, *T
, *E
, *res
, *res1
, *res2
, *one
;
356 one
= DD_ONE(manager
);
359 /* Cube is guaranteed to be a cube at this point. */
360 if (cube
== one
|| F
== one
) {
363 /* From now on, f and cube are non-constant. */
365 /* Abstract a variable that does not appear in f. */
366 while (manager
->perm
[F
->index
] > manager
->perm
[cube
->index
]) {
368 if (cube
== one
) return(f
);
371 /* Check the cache. */
372 if (F
->ref
!= 1 && (res
= cuddCacheLookup2(manager
, Cudd_bddExistAbstract
, f
, cube
)) != NULL
) {
376 /* Compute the cofactors of f. */
377 T
= cuddT(F
); E
= cuddE(F
);
379 T
= Cudd_Not(T
); E
= Cudd_Not(E
);
382 /* If the two indices are the same, so are their levels. */
383 if (F
->index
== cube
->index
) {
384 if (T
== one
|| E
== one
|| T
== Cudd_Not(E
)) {
387 res1
= cuddBddExistAbstractRecur(manager
, T
, cuddT(cube
));
388 if (res1
== NULL
) return(NULL
);
391 cuddCacheInsert2(manager
, Cudd_bddExistAbstract
, f
, cube
, one
);
395 res2
= cuddBddExistAbstractRecur(manager
, E
, cuddT(cube
));
397 Cudd_IterDerefBdd(manager
,res1
);
401 res
= cuddBddAndRecur(manager
, Cudd_Not(res1
), Cudd_Not(res2
));
403 Cudd_IterDerefBdd(manager
, res1
);
404 Cudd_IterDerefBdd(manager
, res2
);
409 Cudd_IterDerefBdd(manager
, res1
);
410 Cudd_IterDerefBdd(manager
, res2
);
412 cuddCacheInsert2(manager
, Cudd_bddExistAbstract
, f
, cube
, res
);
415 } else { /* if (cuddI(manager,F->index) < cuddI(manager,cube->index)) */
416 res1
= cuddBddExistAbstractRecur(manager
, T
, cube
);
417 if (res1
== NULL
) return(NULL
);
419 res2
= cuddBddExistAbstractRecur(manager
, E
, cube
);
421 Cudd_IterDerefBdd(manager
, res1
);
425 /* ITE takes care of possible complementation of res1 and of the
426 ** case in which res1 == res2. */
427 res
= cuddBddIteRecur(manager
, manager
->vars
[F
->index
], res1
, res2
);
429 Cudd_IterDerefBdd(manager
, res1
);
430 Cudd_IterDerefBdd(manager
, res2
);
436 cuddCacheInsert2(manager
, Cudd_bddExistAbstract
, f
, cube
, res
);
440 } /* end of cuddBddExistAbstractRecur */
443 /**Function********************************************************************
445 Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the
448 Description [Takes the exclusive OR of two BDDs and simultaneously abstracts
449 the variables in cube. The variables are existentially abstracted. Returns a
450 pointer to the result is successful; NULL otherwise.]
454 SeeAlso [Cudd_bddAndAbstract]
456 ******************************************************************************/
458 cuddBddXorExistAbstractRecur(
464 DdNode
*F
, *fv
, *fnv
, *G
, *gv
, *gnv
;
465 DdNode
*one
, *zero
, *r
, *t
, *e
, *Cube
;
466 unsigned int topf
, topg
, topcube
, top
, index
;
469 one
= DD_ONE(manager
);
470 zero
= Cudd_Not(one
);
472 /* Terminal cases. */
476 if (f
== Cudd_Not(g
)) {
480 return(cuddBddXorRecur(manager
, f
, g
));
483 return(cuddBddExistAbstractRecur(manager
, Cudd_Not(g
), cube
));
486 return(cuddBddExistAbstractRecur(manager
, Cudd_Not(f
), cube
));
489 return(cuddBddExistAbstractRecur(manager
, g
, cube
));
492 return(cuddBddExistAbstractRecur(manager
, f
, cube
));
495 /* At this point f, g, and cube are not constant. */
497 if (f
> g
) { /* Try to increase cache efficiency. */
504 r
= cuddCacheLookup(manager
, DD_BDD_XOR_EXIST_ABSTRACT_TAG
, f
, g
, cube
);
509 /* Here we can skip the use of cuddI, because the operands are known
510 ** to be non-constant.
513 topf
= manager
->perm
[F
->index
];
515 topg
= manager
->perm
[G
->index
];
516 top
= ddMin(topf
, topg
);
517 topcube
= manager
->perm
[cube
->index
];
520 return(cuddBddXorExistAbstractRecur(manager
, f
, g
, cuddT(cube
)));
522 /* Now, topcube >= top. */
528 if (Cudd_IsComplement(f
)) {
540 if (Cudd_IsComplement(g
)) {
548 if (topcube
== top
) {
554 t
= cuddBddXorExistAbstractRecur(manager
, fv
, gv
, Cube
);
555 if (t
== NULL
) return(NULL
);
557 /* Special case: 1 OR anything = 1. Hence, no need to compute
558 ** the else branch if t is 1.
560 if (t
== one
&& topcube
== top
) {
561 cuddCacheInsert(manager
, DD_BDD_XOR_EXIST_ABSTRACT_TAG
, f
, g
, cube
, one
);
566 e
= cuddBddXorExistAbstractRecur(manager
, fnv
, gnv
, Cube
);
568 Cudd_IterDerefBdd(manager
, t
);
573 if (topcube
== top
) { /* abstract */
574 r
= cuddBddAndRecur(manager
, Cudd_Not(t
), Cudd_Not(e
));
576 Cudd_IterDerefBdd(manager
, t
);
577 Cudd_IterDerefBdd(manager
, e
);
582 Cudd_IterDerefBdd(manager
, t
);
583 Cudd_IterDerefBdd(manager
, e
);
590 if (Cudd_IsComplement(t
)) {
591 r
= cuddUniqueInter(manager
,(int)index
,Cudd_Not(t
),Cudd_Not(e
));
593 Cudd_IterDerefBdd(manager
, t
);
594 Cudd_IterDerefBdd(manager
, e
);
599 r
= cuddUniqueInter(manager
,(int)index
,t
,e
);
601 Cudd_IterDerefBdd(manager
, t
);
602 Cudd_IterDerefBdd(manager
, e
);
609 cuddCacheInsert(manager
, DD_BDD_XOR_EXIST_ABSTRACT_TAG
, f
, g
, cube
, r
);
612 } /* end of cuddBddXorExistAbstractRecur */
615 /**Function********************************************************************
617 Synopsis [Performs the recursive steps of Cudd_bddBoleanDiff.]
619 Description [Performs the recursive steps of Cudd_bddBoleanDiff.
620 Returns the BDD obtained by XORing the cofactors of f with respect to
621 var if successful; NULL otherwise. Exploits the fact that dF/dx =
628 ******************************************************************************/
630 cuddBddBooleanDiffRecur(
635 DdNode
*T
, *E
, *res
, *res1
, *res2
;
638 if (cuddI(manager
,f
->index
) > manager
->perm
[var
->index
]) {
639 /* f does not depend on var. */
640 return(Cudd_Not(DD_ONE(manager
)));
643 /* From now on, f is non-constant. */
645 /* If the two indices are the same, so are their levels. */
646 if (f
->index
== var
->index
) {
647 res
= cuddBddXorRecur(manager
, cuddT(f
), cuddE(f
));
651 /* From now on, cuddI(manager,f->index) < cuddI(manager,cube->index). */
653 /* Check the cache. */
654 res
= cuddCacheLookup2(manager
, cuddBddBooleanDiffRecur
, f
, var
);
659 /* Compute the cofactors of f. */
660 T
= cuddT(f
); E
= cuddE(f
);
662 res1
= cuddBddBooleanDiffRecur(manager
, T
, var
);
663 if (res1
== NULL
) return(NULL
);
665 res2
= cuddBddBooleanDiffRecur(manager
, Cudd_Regular(E
), var
);
667 Cudd_IterDerefBdd(manager
, res1
);
671 /* ITE takes care of possible complementation of res1 and of the
672 ** case in which res1 == res2. */
673 res
= cuddBddIteRecur(manager
, manager
->vars
[f
->index
], res1
, res2
);
675 Cudd_IterDerefBdd(manager
, res1
);
676 Cudd_IterDerefBdd(manager
, res2
);
681 cuddCacheInsert2(manager
, cuddBddBooleanDiffRecur
, f
, var
, res
);
684 } /* end of cuddBddBooleanDiffRecur */
687 /*---------------------------------------------------------------------------*/
688 /* Definition of static functions */
689 /*---------------------------------------------------------------------------*/
691 /**Function********************************************************************
693 Synopsis [Checks whether cube is an BDD representing the product of
696 Description [Returns 1 in case of success; 0 otherwise.]
700 ******************************************************************************/
702 bddCheckPositiveCube(
706 if (Cudd_IsComplement(cube
)) return(0);
707 if (cube
== DD_ONE(manager
)) return(1);
708 if (cuddIsConstant(cube
)) return(0);
709 if (cuddE(cube
) == Cudd_Not(DD_ONE(manager
))) {
710 return(bddCheckPositiveCube(manager
, cuddT(cube
)));
714 } /* end of bddCheckPositiveCube */