#include "calPortInt.h"
Go to the source code of this file.
Data Structures | |
struct | CalBddGenStruct |
Typedefs | |
typedef struct CalBddGenStruct | CalBddGen_t |
Enumerations | |
enum | bdd_gen_type { bdd_gen_cubes, bdd_gen_nodes, bdd_gen_cubes, bdd_gen_nodes } |
Functions | |
static void | pop_node_stack (CalBddGen_t *gen) |
static void | push_node_stack (Cal_Bdd_t f, CalBddGen_t *gen) |
static void | pop_cube_stack (CalBddGen_t *gen) |
static void | push_cube_stack (Cal_Bdd_t f, CalBddGen_t *gen) |
bdd_gen_status | bdd_gen_read_status (bdd_gen *gen) |
bdd_gen * | bdd_first_cube (bdd_t *fn, array_t **cube) |
boolean | bdd_next_cube (bdd_gen *gen_, array_t **cube) |
bdd_gen * | bdd_first_disjoint_cube (bdd_t *fn, array_t **cube) |
boolean | bdd_next_disjoint_cube (bdd_gen *gen_, array_t **cube) |
bdd_gen * | bdd_first_node (bdd_t *fn, bdd_node **node) |
boolean | bdd_next_node (bdd_gen *gen_, bdd_node **node) |
int | bdd_gen_free (bdd_gen *gen_) |
typedef struct CalBddGenStruct CalBddGen_t |
CFile***********************************************************************
FileName [calPortIter.c]
PackageName [calPort]
Synopsis [required]
Description [optional]
SeeAlso [optional]
Author [Rajeev K. Ranjan. Modified from the CMU port package written by Tom Shiple.]
Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. All rights reserved.
Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.]
Definition at line 46 of file calPortIter.c.
enum bdd_gen_type |
Definition at line 51 of file calPortIter.c.
00051 { 00052 bdd_gen_cubes, 00053 bdd_gen_nodes 00054 } bdd_gen_type;
Function********************************************************************
Synopsis [required]
Description [bdd_first_cube - return the first cube of the function. A generator is returned that will iterate over the rest. Return the generator. ]
SideEffects [required]
SeeAlso [optional]
Definition at line 143 of file calPortIter.c.
00144 { 00145 Cal_BddManager_t *manager; 00146 CalBddGen_t *gen; 00147 int i; 00148 long numVars; 00149 Cal_Bdd function; 00150 Cal_Bdd_t calBdd; 00151 00152 if (fn == NIL(bdd_t)) { 00153 CalBddFatalMessage("bdd_first_cube: invalid BDD"); 00154 } 00155 00156 manager = fn->bddManager; 00157 function = fn->calBdd; 00158 00159 /* 00160 * Allocate a new generator structure and fill it in; the stack and the 00161 * cube will be used, but the visited table and the node will not be used. 00162 */ 00163 gen = ALLOC(CalBddGen_t, 1); 00164 00165 /* 00166 * first - init all the members to a rational value for cube iteration 00167 */ 00168 gen->manager = manager; 00169 gen->status = bdd_EMPTY; 00170 gen->type = bdd_gen_cubes; 00171 gen->gen.cubes.cube = NIL(array_t); 00172 gen->stack.sp = 0; 00173 gen->stack.nodeStack = NIL(CalBddNode_t *); 00174 gen->stack.idStack = NIL(int); 00175 gen->node = NIL(CalBddNode_t); 00176 00177 numVars = Cal_BddVars(manager); 00178 gen->gen.cubes.cube = array_alloc(bdd_literal, numVars); 00179 00180 /* 00181 * Initialize each literal to 2 (don't care). 00182 */ 00183 for (i = 0; i < numVars; i++) { 00184 array_insert(bdd_literal, gen->gen.cubes.cube, i, 2); 00185 } 00186 00187 /* 00188 * The stack size will never exceed the number of variables in the BDD, since 00189 * the longest possible path from root to constant 1 is the number 00190 * of variables in the BDD. 00191 */ 00192 gen->stack.sp = 0; 00193 gen->stack.nodeStack = ALLOC(CalBddNode_t *, numVars); 00194 gen->stack.idStack = ALLOC(int, numVars); 00195 00196 /* 00197 * Clear out the stack so that in bdd_gen_free, we can decrement the 00198 * ref count of those nodes still on the stack. 00199 */ 00200 for (i = 0; i < numVars; i++) { 00201 gen->stack.nodeStack[i] = NIL(CalBddNode_t); 00202 gen->stack.idStack[i] = -1; 00203 } 00204 00205 if (Cal_BddIsBddZero(manager, function)){ 00206 /* 00207 * All done, for this was but the zero constant ... 00208 * We are enumerating the onset, (which is vacuous). 00209 * gen->status initialized to bdd_EMPTY above, so this 00210 * appears to be redundant. 00211 */ 00212 gen->status = bdd_EMPTY; 00213 } else { 00214 /* 00215 * Get to work enumerating the onset. Get the first cube. Note that 00216 * if fn is just the constant 1, push_cube_stack will properly 00217 * handle this. 00218 * Get a new pointer to fn->node beforehand: this increments 00219 * the reference count of fn->node; this is necessary, because 00220 * when fn->node 00221 * is popped from the stack at the very end, it's ref count is 00222 * decremented. 00223 */ 00224 gen->status = bdd_NONEMPTY; 00225 calBdd = CalBddGetInternalBdd(manager, function); 00226 push_cube_stack(calBdd, gen); 00227 } 00228 *cube = gen->gen.cubes.cube; 00229 return (bdd_gen *)(gen); 00230 }
Definition at line 257 of file calPortIter.c.
00258 { 00259 return(bdd_first_cube(fn,cube)); 00260 }
Function********************************************************************
Synopsis [required]
Description [bdd_first_node - enumerates all bdd_node in fn. Return the generator.]
SideEffects [required]
SeeAlso [optional]
Definition at line 281 of file calPortIter.c.
00282 { 00283 Cal_BddManager_t *manager; 00284 CalBddGen_t *gen; 00285 long numVars; 00286 int i; 00287 Cal_Bdd_t calBdd; 00288 Cal_Bdd function; 00289 00290 if (fn == NIL(bdd_t)) { 00291 CalBddFatalMessage("bdd_first_node: invalid BDD"); 00292 } 00293 00294 manager = fn->bddManager; 00295 function = fn->calBdd; 00296 00297 /* 00298 * Allocate a new generator structure and fill it in; the 00299 * visited table will be used, as will the stack, but the 00300 * cube array will not be used. 00301 */ 00302 gen = ALLOC(CalBddGen_t, 1); 00303 00304 /* 00305 * first - init all the members to a rational value for node iteration. 00306 */ 00307 gen->manager = manager; 00308 gen->status = bdd_NONEMPTY; 00309 gen->type = bdd_gen_nodes; 00310 gen->gen.nodes.visited = NIL(st_table); 00311 gen->stack.sp = 0; 00312 gen->stack.nodeStack = NIL(CalBddNode_t *); 00313 gen->stack.idStack = NIL(int); 00314 gen->node = NIL(CalBddNode_t); 00315 00316 /* 00317 * Set up the hash table for visited nodes. Every time we visit a node, 00318 * we insert it into the table. 00319 */ 00320 gen->gen.nodes.visited = st_init_table(st_ptrcmp, st_ptrhash); 00321 00322 /* 00323 * The stack size will never exceed the number of variables in the BDD, since 00324 * the longest possible path from root to constant 1 is the number 00325 * of variables in the BDD. 00326 */ 00327 gen->stack.sp = 0; 00328 numVars = Cal_BddVars(manager); 00329 gen->stack.nodeStack = ALLOC(CalBddNode_t *, numVars); 00330 gen->stack.idStack = ALLOC(int, numVars); 00331 /* 00332 * Clear out the stack so that in bdd_gen_free, we can decrement the 00333 * ref count of those nodes still on the stack. 00334 */ 00335 for (i = 0; i < numVars; i++) { 00336 gen->stack.nodeStack[i] = NIL(CalBddNode_t); 00337 gen->stack.idStack[i] = -1; 00338 } 00339 00340 /* 00341 * Get the first node. Get a new pointer to fn->node beforehand: 00342 * this increments 00343 * the reference count of fn->node; this is necessary, because when fn->node 00344 * is popped from the stack at the very end, it's ref count is decremented. 00345 */ 00346 calBdd = CalBddGetInternalBdd(manager, function); 00347 push_node_stack(calBdd, gen); 00348 gen->status = bdd_NONEMPTY; 00349 00350 *node = (bdd_node *)gen->node; /* return the node */ 00351 return (bdd_gen *)(gen); /* and the new generator */ 00352 }
int bdd_gen_free | ( | bdd_gen * | gen_ | ) |
Function********************************************************************
Synopsis [required]
Description [bdd_gen_free - frees up the space used by the generator. Return an int so that it is easier to fit in a foreach macro. Return 0 (to make it easy to put in expressions). ]
SideEffects [required]
SeeAlso [optional]
Definition at line 392 of file calPortIter.c.
00393 { 00394 CalBddGen_t *gen = (CalBddGen_t *) gen_; 00395 st_table *visited_table; 00396 00397 switch (gen->type) { 00398 case bdd_gen_cubes: 00399 array_free(gen->gen.cubes.cube); 00400 gen->gen.cubes.cube = NIL(array_t); 00401 break; 00402 case bdd_gen_nodes: 00403 visited_table = gen->gen.nodes.visited; 00404 st_free_table(visited_table); 00405 visited_table = NIL(st_table); 00406 break; 00407 } 00408 FREE(gen->stack.nodeStack); 00409 FREE(gen->stack.idStack); 00410 FREE(gen); 00411 return (0); /* make it return some sort of an int */ 00412 }
bdd_gen_status bdd_gen_read_status | ( | bdd_gen * | gen | ) |
AutomaticEnd
Definition at line 124 of file calPortIter.c.
00125 { 00126 return ((CalBddGen_t *)gen)->status; 00127 }
Function********************************************************************
Synopsis [required]
Description [bdd_next_cube - get the next cube on the generator. Returns {TRUE, FALSE} when {more, no more}.]
SideEffects [required]
SeeAlso [optional]
Definition at line 245 of file calPortIter.c.
00246 { 00247 CalBddGen_t *gen = (CalBddGen_t *) gen_; 00248 pop_cube_stack(gen); 00249 if (gen->status == bdd_EMPTY) { 00250 return (FALSE); 00251 } 00252 *cube = gen->gen.cubes.cube; 00253 return (TRUE); 00254 }
Definition at line 263 of file calPortIter.c.
00264 { 00265 return(bdd_next_cube(gen_,cube)); 00266 }
Function********************************************************************
Synopsis [required]
Description [bdd_next_node - get the next node in the BDD. Return {TRUE, FALSE} when {more, no more}. ]
SideEffects [required]
SeeAlso [optional]
Definition at line 367 of file calPortIter.c.
00368 { 00369 CalBddGen_t *gen = (CalBddGen_t *) gen_; 00370 pop_node_stack(gen); 00371 if (gen->status == bdd_EMPTY) { 00372 return (FALSE); 00373 } 00374 *node = (bdd_node *) gen->node; 00375 return (TRUE); 00376 }
static void pop_cube_stack | ( | CalBddGen_t * | gen | ) | [static] |
Function********************************************************************
Synopsis [required]
Description [optional]
SideEffects [required]
SeeAlso [optional]
Definition at line 509 of file calPortIter.c.
00510 { 00511 CalBddNode_t *fNode; 00512 int fId, fIndex, i; 00513 Cal_Bdd_t f1, f; 00514 Cal_BddManager_t *manager; 00515 00516 manager = gen->manager; 00517 if (gen->stack.sp == 0) { 00518 /* 00519 * Stack is empty. Have already explored both the 0 and 1 branches of 00520 * the root of the BDD. 00521 */ 00522 gen->status = bdd_EMPTY; 00523 } else { 00524 /* 00525 * Explore the 1 branch of the node at the top of the stack (since it is 00526 * on the stack, this means we have already explored the 0 branch). We 00527 * permanently pop the top node, and bdd_free it, since there are 00528 * no more edges left to explore. 00529 */ 00530 fNode = gen->stack.nodeStack[--gen->stack.sp]; 00531 fId = gen->stack.idStack[gen->stack.sp]; 00532 gen->stack.nodeStack[gen->stack.sp] = NIL(CalBddNode_t); /* overwrite */ 00533 /* with NIL */ 00534 gen->stack.idStack[gen->stack.sp] = -1; 00535 array_insert(bdd_literal, gen->gen.cubes.cube, fId-1, 1); 00536 fIndex = manager->idToIndex[fId]; 00537 for (i = fIndex + 1; i < array_n(gen->gen.cubes.cube); i++) { 00538 array_insert(bdd_literal, gen->gen.cubes.cube, 00539 manager->indexToId[i]-1, 2); 00540 } 00541 f.bddNode = fNode; 00542 f.bddId = fId; 00543 CalBddGetThenBdd(f, f1); 00544 push_cube_stack(f1, gen); 00545 } 00546 }
static void pop_node_stack | ( | CalBddGen_t * | gen | ) | [static] |
AutomaticStart
Function********************************************************************
Synopsis [required]
Description [optional]
SideEffects [required]
SeeAlso [optional]
Definition at line 649 of file calPortIter.c.
00650 { 00651 CalBddNode_t *fNode; 00652 int fId; 00653 Cal_Bdd_t calBdd; 00654 00655 if (gen->stack.sp == 0) { 00656 gen->status = bdd_EMPTY; 00657 return; 00658 } 00659 fNode = gen->stack.nodeStack[--gen->stack.sp]; 00660 fId = gen->stack.idStack[gen->stack.sp]; 00661 gen->stack.nodeStack[gen->stack.sp] = NIL(CalBddNode_t); 00662 gen->stack.idStack[gen->stack.sp] = -1; 00663 calBdd.bddNode = fNode; 00664 calBdd.bddId = fId; 00665 push_node_stack(calBdd, gen); 00666 }
static void push_cube_stack | ( | Cal_Bdd_t | f, | |
CalBddGen_t * | gen | |||
) | [static] |
Function********************************************************************
Synopsis [required]
Description [push_cube_stack - push a cube onto the stack to visit. Return nothing, just do it. The BDD is traversed using depth-first search, with the ELSE branch searched before the THEN branch. Caution: If you are creating new BDD's while iterating through the cubes, and a garbage collection happens to be performed during this process, then the BDD generator will get lost and an error will result. ]
SideEffects [required]
SeeAlso [optional]
Definition at line 448 of file calPortIter.c.
00449 { 00450 bdd_variableId topId; 00451 Cal_Bdd_t f0, f1; 00452 Cal_BddManager_t *manager; 00453 00454 manager = gen->manager; 00455 00456 if (CalBddIsBddOne(manager, f)){ 00457 return; 00458 } 00459 00460 topId = f.bddId-1; 00461 CalBddGetElseBdd(f, f0); 00462 CalBddGetThenBdd(f, f1); 00463 00464 if (CalBddIsBddZero(manager, f1)){ 00465 /* 00466 * No choice: take the 0 branch. Since there is only one branch to 00467 * explore from f, there is no need to push f onto the stack, because 00468 * after exploring this branch we are done with f. A consequence of 00469 * this is that there will be no f to pop either. Same goes for the 00470 * next case. Decrement the ref count of f and of the branch leading 00471 * to zero, since we will no longer need to access these nodes. 00472 */ 00473 array_insert(bdd_literal, gen->gen.cubes.cube, topId, 0); 00474 push_cube_stack(f0, gen); 00475 } 00476 else if (CalBddIsBddZero(manager, f0)){ 00477 /* 00478 * No choice: take the 1 branch 00479 */ 00480 array_insert(bdd_literal, gen->gen.cubes.cube, topId, 1); 00481 push_cube_stack(f1, gen); 00482 } else { 00483 /* 00484 * In this case, we must explore both branches of f. We always choose 00485 * to explore the 0 branch first. We must push f on the stack, so that 00486 * we can later pop it and explore its 1 branch. Decrement the ref count 00487 * of f1 since we will no longer need to access this node. Note that 00488 * the parent of f1 was bdd_freed above or in pop_cube_stack. 00489 */ 00490 gen->stack.nodeStack[gen->stack.sp] = f.bddNode; 00491 gen->stack.idStack[gen->stack.sp++] = f.bddId; 00492 array_insert(bdd_literal, gen->gen.cubes.cube, topId, 0); 00493 push_cube_stack(f0, gen); 00494 } 00495 }
static void push_node_stack | ( | Cal_Bdd_t | f, | |
CalBddGen_t * | gen | |||
) | [static] |
Function********************************************************************
Synopsis [required]
Description [push_node_stack - push a node onto the stack. The same as push_cube_stack but for enumerating nodes instead of cubes. The BDD is traversed using depth-first search, with the ELSE branch searched before the THEN branch, and a node returned only after its children have been returned. Note that the returned bdd_node pointer has the complement bit zeroed out. Caution: If you are creating new BDD's while iterating through the nodes, and a garbage collection happens to be performed during this process, then the BDD generator will get lost and an error will result. ]
SideEffects [required]
SeeAlso [optional]
Definition at line 568 of file calPortIter.c.
00569 { 00570 Cal_Bdd_t f0, f1; 00571 bdd_node *reg_f, *reg_f0, *reg_f1; 00572 00573 reg_f = (CalBddNode_t *) CAL_BDD_POINTER(f.bddNode); /* use of calInt.h */ 00574 if (st_is_member(gen->gen.nodes.visited, (char *) reg_f)){ 00575 /* 00576 * Already been visited. 00577 */ 00578 return; 00579 } 00580 00581 if (CalBddIsBddConst(f)){ 00582 /* 00583 * If f is the constant node and it has not been visited yet, then 00584 * put it in the visited table and set the gen->node pointer. 00585 * There is no need to put it in the stack because 00586 * the constant node does not have any branches, and there is no 00587 * need to free f because constant nodes have a saturated 00588 * reference count. 00589 */ 00590 st_insert(gen->gen.nodes.visited, (char *) reg_f, NIL(char)); 00591 gen->node = (CalBddNode_t *) reg_f; 00592 } else { 00593 /* 00594 * f has not been marked as visited. We don't know yet if any of 00595 * its branches remain to be explored. First get its branches. 00596 */ 00597 CalBddGetElseBdd(f, f0); 00598 CalBddGetThenBdd(f, f1); 00599 00600 reg_f0 = (CalBddNode_t *) CAL_BDD_POINTER(f0.bddNode); 00601 reg_f1 = (CalBddNode_t *) CAL_BDD_POINTER(f1.bddNode); 00602 00603 if (st_is_member(gen->gen.nodes.visited, (char *) reg_f0) == 0){ 00604 /* 00605 * The 0 child has not been visited, so explore the 0 branch. 00606 * First push f on the stack. Bdd_free f1 since we will not 00607 * need to access this exact pointer any more. 00608 */ 00609 gen->stack.nodeStack[gen->stack.sp] = f.bddNode; 00610 gen->stack.idStack[gen->stack.sp++] = f.bddId; 00611 push_node_stack(f0, gen); 00612 } else{ 00613 if (st_is_member(gen->gen.nodes.visited, (char *) reg_f1) == 0){ 00614 /* 00615 * The 0 child has been visited, but the 1 child has not been 00616 * visited, so explore the 1 branch. First push f on the 00617 * stack. 00618 */ 00619 gen->stack.nodeStack[gen->stack.sp] = f.bddNode; 00620 gen->stack.idStack[gen->stack.sp++] = f.bddId; 00621 push_node_stack(f1, gen); 00622 } else { 00623 /* 00624 * Both the 0 and 1 children have been visited. Thus we are done 00625 * exploring from f. 00626 * Mark f as visited (put it in the visited table), and set the 00627 * gen->node pointer. 00628 */ 00629 st_insert(gen->gen.nodes.visited, (char *) reg_f, NIL(char)); 00630 gen->node = (CalBddNode_t *) reg_f; 00631 } 00632 } 00633 } 00634 }