src/cmuPort/cmuPortIter.c File Reference

#include "cmuPortInt.h"
Include dependency graph for cmuPortIter.c:

Go to the source code of this file.

Data Structures

struct  cmu_bdd_gen

Enumerations

enum  bdd_gen_type { bdd_gen_cubes, bdd_gen_nodes, bdd_gen_cubes, bdd_gen_nodes }

Functions

static void pop_cube_stack (cmu_bdd_gen *gen)
static void pop_node_stack (cmu_bdd_gen *gen)
static void push_cube_stack (bdd_node *f, cmu_bdd_gen *gen)
static void push_node_stack (bdd_node *f, cmu_bdd_gen *gen)
bdd_gen_status bdd_gen_read_status (bdd_gen *gen)
bdd_genbdd_first_cube (bdd_t *fn, array_t **cube)
boolean bdd_next_cube (bdd_gen *gen_, array_t **cube)
bdd_genbdd_first_disjoint_cube (bdd_t *fn, array_t **cube)
boolean bdd_next_disjoint_cube (bdd_gen *gen_, array_t **cube)
bdd_genbdd_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_)

Enumeration Type Documentation

CFile***********************************************************************

FileName [cmuPort.c]

PackageName [cmu_port]

Synopsis [Port routines for CMU package.]

Description [optional]

SeeAlso [optional]

Author [Thomas R. Shiple. Some changes by Rajeev K. Ranjan.]

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.]

Revision [

Id
cmuPortIter.c,v 1.4 2005/04/15 23:24:39 fabio Exp

]

Enumerator:
bdd_gen_cubes 
bdd_gen_nodes 
bdd_gen_cubes 
bdd_gen_nodes 

Definition at line 51 of file cmuPortIter.c.

00051              {
00052     bdd_gen_cubes,
00053     bdd_gen_nodes
00054 } bdd_gen_type;


Function Documentation

bdd_gen* bdd_first_cube ( bdd_t fn,
array_t **  cube 
)

Definition at line 132 of file cmuPortIter.c.

00133 {
00134     struct bdd_manager_ *manager;
00135     cmu_bdd_gen *gen;
00136     int i;
00137     long num_vars;
00138     bdd_node *f;
00139 
00140     if (fn == NIL(bdd_t)) {
00141         cmu_bdd_fatal("bdd_first_cube: invalid BDD");
00142     }
00143 
00144     manager = fn->mgr;
00145 
00146     /*
00147      *    Allocate a new generator structure and fill it in; the stack and the 
00148      *    cube will be used, but the visited table and the node will not be used.
00149      */
00150     gen = ALLOC(cmu_bdd_gen, 1);
00151     if (gen == NIL(cmu_bdd_gen)) {
00152         cmu_bdd_fatal("bdd_first_cube: failed on memory allocation, location 1");
00153     }
00154 
00155     /*
00156      *    first - init all the members to a rational value for cube iteration
00157      */
00158     gen->manager = manager;
00159     gen->status = bdd_EMPTY;
00160     gen->type = bdd_gen_cubes;
00161     gen->gen.cubes.cube = NIL(array_t);
00162     gen->stack.sp = 0;
00163     gen->stack.stack = NIL(bdd_node *);
00164     gen->node = NIL(bdd_node);
00165 
00166     num_vars = cmu_bdd_vars(manager);
00167     gen->gen.cubes.cube = array_alloc(bdd_literal, num_vars);
00168     if (gen->gen.cubes.cube == NIL(array_t)) {
00169         cmu_bdd_fatal("bdd_first_cube: failed on memory allocation, location 2");
00170     }
00171     
00172     /*
00173      * Initialize each literal to 2 (don't care).
00174      */
00175     for (i = 0; i < num_vars; i++) {
00176         array_insert(bdd_literal, gen->gen.cubes.cube, i, 2);
00177     }
00178 
00179     /*
00180      * The stack size will never exceed the number of variables in the BDD, since
00181      * the longest possible path from root to constant 1 is the number of variables 
00182      * in the BDD.
00183      */
00184     gen->stack.sp = 0;
00185     gen->stack.stack = ALLOC(bdd_node *, num_vars);
00186     if (gen->stack.stack == NIL(bdd_node *)) {
00187         cmu_bdd_fatal("bdd_first_cube: failed on memory allocation, location 3");
00188     }
00189     /*
00190      * Clear out the stack so that in bdd_gen_free, we can decrement the ref count
00191      * of those nodes still on the stack.
00192      */
00193     for (i = 0; i < num_vars; i++) {
00194         gen->stack.stack[i] = NIL(bdd_node);
00195     }
00196 
00197     if (bdd_is_tautology(fn, 0)) {
00198         /*
00199          *    All done, for this was but the zero constant ...
00200          *    We are enumerating the onset, (which is vacuous).
00201          *    gen->status initialized to bdd_EMPTY above, so this
00202          *    appears to be redundant.
00203          */
00204         gen->status = bdd_EMPTY;
00205     } else {
00206         /*
00207          *    Get to work enumerating the onset.  Get the first cube.  Note that
00208          *    if fn is just the constant 1, push_cube_stack will properly handle this.
00209          *    Get a new pointer to fn->node beforehand: this increments
00210          *    the reference count of fn->node; this is necessary, because when fn->node
00211          *    is popped from the stack at the very end, it's ref count is decremented.
00212          */
00213         gen->status = bdd_NONEMPTY;
00214         f = cmu_bdd_identity(manager, fn->node);
00215         push_cube_stack(f, gen);
00216     }
00217 
00218     *cube = gen->gen.cubes.cube;
00219     return (bdd_gen *)(gen);
00220 }

bdd_gen* bdd_first_disjoint_cube ( bdd_t fn,
array_t **  cube 
)

Definition at line 239 of file cmuPortIter.c.

00240 {
00241   return(bdd_first_cube(fn,cube));
00242 }

bdd_gen* bdd_first_node ( bdd_t fn,
bdd_node **  node 
)

Definition at line 255 of file cmuPortIter.c.

00256 {
00257     struct bdd_manager_ *manager;
00258     cmu_bdd_gen *gen;
00259     long num_vars;
00260     bdd_node *f;
00261     int i;
00262 
00263     if (fn == NIL(bdd_t)) {
00264         cmu_bdd_fatal("bdd_first_node: invalid BDD");
00265     }
00266 
00267     manager = fn->mgr;
00268 
00269     /*
00270      *    Allocate a new generator structure and fill it in; the
00271      *    visited table will be used, as will the stack, but the
00272      *    cube array will not be used.
00273      */
00274     gen = ALLOC(cmu_bdd_gen, 1);
00275     if (gen == NIL(bdd_gen)) {
00276         cmu_bdd_fatal("bdd_first_node: failed on memory allocation, location 1");
00277     }
00278 
00279     /*
00280      *    first - init all the members to a rational value for node iteration.
00281      */
00282     gen->manager = manager;
00283     gen->status = bdd_NONEMPTY;
00284     gen->type = bdd_gen_nodes;
00285     gen->gen.nodes.visited = NIL(st_table);
00286     gen->stack.sp = 0;
00287     gen->stack.stack = NIL(bdd_node *);
00288     gen->node = NIL(bdd_node);
00289   
00290     /* 
00291      * Set up the hash table for visited nodes.  Every time we visit a node,
00292      * we insert it into the table.
00293      */
00294     gen->gen.nodes.visited = st_init_table(st_ptrcmp, st_ptrhash);
00295     if (gen->gen.nodes.visited == NIL(st_table)) {
00296         cmu_bdd_fatal("bdd_first_node: failed on memory allocation, location 2");
00297     }
00298 
00299     /*
00300      * The stack size will never exceed the number of variables in the BDD, since
00301      * the longest possible path from root to constant 1 is the number of variables 
00302      * in the BDD.
00303      */
00304     gen->stack.sp = 0;
00305     num_vars = cmu_bdd_vars(manager);
00306     gen->stack.stack = ALLOC(bdd_node *, num_vars);
00307     if (gen->stack.stack == NIL(bdd_node *)) {
00308         cmu_bdd_fatal("bdd_first_node: failed on memory allocation, location 3");
00309     }
00310     /*
00311      * Clear out the stack so that in bdd_gen_free, we can decrement the ref count
00312      * of those nodes still on the stack.
00313      */
00314     for (i = 0; i < num_vars; i++) {
00315         gen->stack.stack[i] = NIL(bdd_node);
00316     }
00317 
00318     /*
00319      * Get the first node.  Get a new pointer to fn->node beforehand: this increments
00320      * the reference count of fn->node; this is necessary, because when fn->node
00321      * is popped from the stack at the very end, it's ref count is decremented.
00322      */
00323     f = cmu_bdd_identity(manager, fn->node);
00324     push_node_stack(f, gen);
00325     gen->status = bdd_NONEMPTY;
00326 
00327     *node = gen->node;  /* return the node */
00328     return (bdd_gen *) (gen);   /* and the new generator */
00329 }

int bdd_gen_free ( bdd_gen gen_  ) 

Definition at line 354 of file cmuPortIter.c.

00355 {
00356     long num_vars;
00357     int i;
00358     struct bdd_manager_ *mgr;
00359     bdd_node *f;
00360     st_table *visited_table;
00361     st_generator *visited_gen;
00362     cmu_bdd_gen *gen = (cmu_bdd_gen *) gen_;
00363 
00364     mgr = gen->manager;
00365 
00366     switch (gen->type) {
00367     case bdd_gen_cubes:
00368         array_free(gen->gen.cubes.cube);
00369         gen->gen.cubes.cube = NIL(array_t);
00370         break;
00371     case bdd_gen_nodes:
00372         visited_table = gen->gen.nodes.visited;
00373         st_foreach_item(visited_table, visited_gen, &f, NIL(refany)) {
00374             cmu_bdd_free(mgr, (bdd) f);
00375         }
00376         st_free_table(visited_table);
00377         visited_table = NIL(st_table);
00378         break;
00379     }
00380 
00381     /*
00382      * Free the data associated with this generator.  If there are any nodes remaining
00383      * on the stack, we must free them, to get their ref counts back to what they were before.
00384      */
00385     num_vars = cmu_bdd_vars(mgr);
00386     for (i = 0; i < num_vars; i++) {
00387         f = gen->stack.stack[i];
00388         if (f != NIL(bdd_node)) {
00389             cmu_bdd_free(mgr, (bdd) f);
00390         }
00391     }
00392     FREE(gen->stack.stack);
00393 
00394     FREE(gen);
00395 
00396     return (0); /* make it return some sort of an int */
00397 }

bdd_gen_status bdd_gen_read_status ( bdd_gen gen  ) 

AutomaticEnd

Definition at line 110 of file cmuPortIter.c.

00111 {
00112   return ((cmu_bdd_gen *)gen)->status;
00113 }

boolean bdd_next_cube ( bdd_gen gen_,
array_t **  cube 
)

Definition at line 227 of file cmuPortIter.c.

00228 {
00229   cmu_bdd_gen *gen = (cmu_bdd_gen *) gen_;
00230   pop_cube_stack(gen);
00231   if (gen->status == bdd_EMPTY) {
00232     return (FALSE);
00233   }
00234   *cube = gen->gen.cubes.cube;
00235   return (TRUE);
00236 }

boolean bdd_next_disjoint_cube ( bdd_gen gen_,
array_t **  cube 
)

Definition at line 245 of file cmuPortIter.c.

00246 {
00247   return(bdd_next_cube(gen_,cube));
00248 }

boolean bdd_next_node ( bdd_gen gen_,
bdd_node **  node 
)

Definition at line 336 of file cmuPortIter.c.

00337 {
00338   cmu_bdd_gen *gen = (cmu_bdd_gen *) gen_;
00339   
00340     pop_node_stack(gen);
00341     if (gen->status == bdd_EMPTY) {
00342         return (FALSE);
00343     }
00344     *node = gen->node;
00345     return (TRUE);
00346 }

static void pop_cube_stack ( cmu_bdd_gen gen  )  [static]

AutomaticStart

Definition at line 486 of file cmuPortIter.c.

00487 {
00488     bdd_variableId topf_id, level_i_id;
00489     bdd_node *branch_f;
00490     bdd_node *f1;
00491     int i;
00492     long topf_level;
00493     struct bdd_manager_ *mgr;
00494     struct bdd_ *var_bdd;
00495 
00496     mgr = gen->manager;
00497 
00498     if (gen->stack.sp == 0) {
00499         /*
00500          * Stack is empty.  Have already explored both the 0 and 1 branches of 
00501          * the root of the BDD.
00502          */
00503         gen->status = bdd_EMPTY;
00504     } else {
00505         /*
00506          * Explore the 1 branch of the node at the top of the stack (since it is
00507          * on the stack, this means we have already explored the 0 branch).  We 
00508          * permanently pop the top node, and bdd_free it, since there are no more edges left to 
00509          * explore. 
00510          */
00511         branch_f = gen->stack.stack[--gen->stack.sp];
00512         gen->stack.stack[gen->stack.sp] = NIL(bdd_node); /* overwrite with NIL */
00513         topf_id = (bdd_variableId) (cmu_bdd_if_id(mgr, (bdd) branch_f) - 1);
00514         array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 1);
00515 
00516         /* 
00517          * We must set the variables with levels greater than the level of branch_f,
00518          * back to 2 (don't care).  This is because these variables are not
00519          * on the current path, and thus there values are don't care.
00520          *
00521          * Note the following correspondence:
00522          *   CMU          UCB
00523          *  index         level   (both start at zero)
00524          *  indexindex    id      (CMU has id 0 for constant, thus really start numbering at 1;
00525          *                                           UCB starts numbering at 0)
00526          */
00527         topf_level = cmu_bdd_if_index(mgr, (bdd) branch_f);
00528         for (i = topf_level + 1; i < array_n(gen->gen.cubes.cube); i++) {
00529             var_bdd = cmu_bdd_var_with_index(mgr, i);
00530             level_i_id = (bdd_variableId) (cmu_bdd_if_id(mgr, var_bdd) - 1);
00531             /*
00532              * No need to free var_bdd, since single variable BDDs are never garbage collected.
00533              * Note that level_i_id is just (mgr->indexindexes[i] - 1); however, wanted
00534              * to avoid using CMU internals.
00535              */
00536             array_insert(bdd_literal, gen->gen.cubes.cube, level_i_id, 2);
00537         }
00538         f1 = cmu_bdd_then(mgr, (bdd) branch_f);
00539         push_cube_stack(f1, gen);
00540         cmu_bdd_free(mgr, (bdd) branch_f);
00541     }
00542 }

static void pop_node_stack ( cmu_bdd_gen gen  )  [static]

Definition at line 630 of file cmuPortIter.c.

00631 {
00632     bdd_node *branch_f;
00633 
00634     if (gen->stack.sp == 0) {
00635         gen->status = bdd_EMPTY;
00636     } else {
00637         branch_f = gen->stack.stack[--gen->stack.sp];  /* overwrite with NIL */
00638         gen->stack.stack[gen->stack.sp] = NIL(bdd_node);
00639         push_node_stack(branch_f, gen);
00640     }
00641 }

static void push_cube_stack ( bdd_node f,
cmu_bdd_gen gen 
) [static]

Definition at line 428 of file cmuPortIter.c.

00429 {
00430     bdd_variableId topf_id;
00431     bdd_node *f0, *f1;
00432     struct bdd_manager_ *mgr;
00433 
00434     mgr = gen->manager;
00435 
00436     if (f == cmu_bdd_one(mgr)) {
00437         return;
00438     }
00439 
00440     topf_id = (bdd_variableId) (cmu_bdd_if_id(mgr, (bdd) f) - 1);
00441 
00442     /* 
00443      * Get the then and else branches of f. Note that cmu_bdd_then and cmu_bdd_else 
00444      * automatically take care of inverted pointers.  
00445      */
00446     f0 = cmu_bdd_else(mgr, (bdd) f);
00447     f1 = cmu_bdd_then(mgr, (bdd) f);
00448 
00449     if (f1 == cmu_bdd_zero(mgr)) {
00450         /*
00451          *    No choice: take the 0 branch.  Since there is only one branch to 
00452          *    explore from f, there is no need to push f onto the stack, because
00453          *    after exploring this branch we are done with f.  A consequence of 
00454          *    this is that there will be no f to pop either.  Same goes for the
00455          *    next case.  Decrement the ref count of f and of the branch leading
00456          *    to zero, since we will no longer need to access these nodes.
00457          */
00458         array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 0);
00459         push_cube_stack(f0, gen);
00460         cmu_bdd_free(mgr, (bdd) f1);
00461         cmu_bdd_free(mgr, (bdd) f);
00462     } else if (f0 == cmu_bdd_zero(mgr)) {
00463         /*
00464          *    No choice: take the 1 branch
00465          */
00466         array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 1);
00467         push_cube_stack(f1, gen);
00468         cmu_bdd_free(mgr, (bdd) f0);
00469         cmu_bdd_free(mgr, (bdd) f);
00470     } else {
00471         /*
00472          * In this case, we must explore both branches of f.  We always choose
00473          * to explore the 0 branch first.  We must push f on the stack, so that
00474          * we can later pop it and explore its 1 branch. Decrement the ref count 
00475          * of f1 since we will no longer need to access this node.  Note that 
00476          * the parent of f1 was bdd_freed above or in pop_cube_stack.
00477          */
00478         gen->stack.stack[gen->stack.sp++] = f;
00479         array_insert(bdd_literal, gen->gen.cubes.cube, topf_id, 0);
00480         push_cube_stack(f0, gen);
00481         cmu_bdd_free(mgr, (bdd) f1);
00482     }
00483 }

static void push_node_stack ( bdd_node f,
cmu_bdd_gen gen 
) [static]

Definition at line 560 of file cmuPortIter.c.

00561 {
00562     bdd_node *f0, *f1;
00563     bdd_node *reg_f, *reg_f0, *reg_f1;
00564     struct bdd_manager_ *mgr;
00565 
00566     mgr = gen->manager;
00567 
00568     reg_f = (bdd_node *) BDD_POINTER(f);  /* use of bddint.h */
00569     if (st_lookup(gen->gen.nodes.visited, (refany) reg_f, NIL(refany))) {
00570         /* 
00571          * Already been visited.
00572          */
00573         return;
00574     }
00575 
00576     if (f == cmu_bdd_one(mgr) || f == cmu_bdd_zero(mgr)) {
00577         /*
00578          * If f is the constant node and it has not been visited yet, then put it in the visited table
00579          * and set the gen->node pointer.  There is no need to put it in the stack because
00580          * the constant node does not have any branches, and there is no need to free f because 
00581          * constant nodes have a saturated reference count.
00582          */
00583         st_insert(gen->gen.nodes.visited, (refany) reg_f, NIL(any));
00584         gen->node = reg_f;
00585     } else {
00586         /*
00587          * f has not been marked as visited.  We don't know yet if any of its branches 
00588          * remain to be explored.  First get its branches.  Note that cmu_bdd_then and 
00589          * cmu_bdd_else automatically take care of inverted pointers.  
00590          */
00591         f0 = cmu_bdd_else(mgr, (bdd) f);
00592         f1 = cmu_bdd_then(mgr, (bdd) f);
00593 
00594         reg_f0 = (bdd_node *) BDD_POINTER(f0);  /* use of bddint.h */
00595         reg_f1 = (bdd_node *) BDD_POINTER(f1);
00596         if (! st_lookup(gen->gen.nodes.visited, (refany) reg_f0, NIL(refany))) {
00597             /* 
00598              * The 0 child has not been visited, so explore the 0 branch.  First push f on 
00599              * the stack.  Bdd_free f1 since we will not need to access this exact pointer
00600              * any more.
00601              */
00602             gen->stack.stack[gen->stack.sp++] = f;
00603             push_node_stack(f0, gen);
00604             cmu_bdd_free(mgr, (bdd) f1);
00605         } else if (! st_lookup(gen->gen.nodes.visited, (refany) reg_f1, NIL(refany))) {
00606             /* 
00607              * The 0 child has been visited, but the 1 child has not been visited, so 
00608              * explore the 1 branch.  First push f on the stack. We are done with f0, 
00609              * so bdd_free it.
00610              */
00611             gen->stack.stack[gen->stack.sp++] = f;
00612             push_node_stack(f1, gen);
00613             cmu_bdd_free(mgr, (bdd) f0);
00614         } else {
00615             /*
00616              * Both the 0 and 1 children have been visited. Thus we are done exploring from f.  
00617              * Mark f as visited (put it in the visited table), and set the gen->node pointer.
00618              * We will no longer need to refer to f0 and f1, so bdd_free them.  f will be
00619              * bdd_freed when the visited table is freed.
00620              */
00621             st_insert(gen->gen.nodes.visited, (refany) reg_f, NIL(any));
00622             gen->node = reg_f;
00623             cmu_bdd_free(mgr, (bdd) f0);
00624             cmu_bdd_free(mgr, (bdd) f1);
00625         }
00626     }
00627 }


Generated on Tue Jan 12 13:57:16 2010 for glu-2.2 by  doxygen 1.6.1