VIS

src/ntk/ntkFlt.c

Go to the documentation of this file.
00001 
00032 #include "ntkInt.h"
00033 
00034 static char rcsid[] UNUSED = "$Id: ntkFlt.c,v 1.13 2009/04/11 22:17:58 fabio Exp $";
00035 
00036 /*---------------------------------------------------------------------------*/
00037 /* Constant declarations                                                     */
00038 /*---------------------------------------------------------------------------*/
00039 #define MAX_NUMBER_BDD_VARS 500
00040 
00041 
00042 /*---------------------------------------------------------------------------*/
00043 /* Macro declarations                                                        */
00044 /*---------------------------------------------------------------------------*/
00045 
00046 
00049 /*---------------------------------------------------------------------------*/
00050 /* Static function prototypes                                                */
00051 /*---------------------------------------------------------------------------*/
00052 
00053 static void NetworkBuildFormalToActualTableRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode);
00054 static void NetworkCreateNodesRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode);
00055 static void NodeCreateAsNecessary(Ntk_Network_t *network, char *nodeName, Var_Variable_t *var);
00056 static boolean NetworkDeclareNodesRecursively(Ntk_Network_t *network, Hrc_Node_t *hrcNode, boolean buildMvfs, mdd_manager **mddMgr);
00057 static array_t * LocalArrayJoin(array_t *array1, array_t *array2);
00058 static array_t * TableCreateFormalInputNameArray(Tbl_Table_t *table, char *namePrefix);
00059 static void NameArrayFree(array_t *nameArray);
00060 static boolean NetworkAbstractNodes(Ntk_Network_t *network, lsList abstractedNames);
00061 static boolean NodeDeclareWithTable(Ntk_Node_t *node, Tbl_Table_t *table, int outIndex, char *path, boolean buildMvfs, mdd_manager *mddMgr);
00062 static void NetworkDeclareIONodes(Ntk_Network_t *network, Hrc_Node_t *hrcNode);
00063 static void NetworkDeclareLatches(Ntk_Network_t *network, Hrc_Node_t *hrcNode);
00064 static void MddManagerResetIfNecessary(mdd_manager **mddMgr);
00065 static Mvf_Function_t * LocalMvfFunctionForTable(Tbl_Table_t *table, int outIndex, mdd_manager *mddMgr, array_t *varMap, int *offset);
00066 
00070 /*---------------------------------------------------------------------------*/
00071 /* Definition of exported functions                                          */
00072 /*---------------------------------------------------------------------------*/
00073 
00117 Ntk_Network_t *
00118 Ntk_HrcNodeConvertToNetwork(
00119   Hrc_Node_t *hrcNode,
00120   boolean     buildMvfs,
00121   lsList abstractedNames)
00122 {
00123   mdd_manager   *mddMgr;
00124   boolean        status1     = TRUE;
00125   boolean        status2     = TRUE;
00126   char          *hrcNodeName = Hrc_NodeReadInstanceName(hrcNode);
00127   Ntk_Network_t *network     = Ntk_NetworkAlloc(hrcNodeName);
00128 
00129   NetworkBuildFormalToActualTableRecursively(network, hrcNode);
00130   NetworkCreateNodesRecursively(network, hrcNode);
00131 
00132   /*
00133    * The MDD manager is for building temporary MDDs.  For robustness, enable
00134    * reordering.
00135    */
00136   mddMgr = mdd_init_empty();
00137   bdd_dynamic_reordering(mddMgr, BDD_REORDER_SIFT, BDD_REORDER_VERBOSITY_DEFAULT);
00138   status1 = NetworkDeclareNodesRecursively(network, hrcNode, buildMvfs, &mddMgr);
00139   mdd_quit(mddMgr);
00140 
00141   if (abstractedNames != (lsList) NULL) {
00142     status2 = NetworkAbstractNodes(network, abstractedNames);
00143   }
00144 
00145   if (!(status1 && status2)) {
00146     Ntk_NetworkFree(network);
00147     return NIL(Ntk_Network_t);
00148   }
00149   else {
00150     return network;
00151   }
00152 }
00153 
00154 
00155 /*---------------------------------------------------------------------------*/
00156 /* Definition of internal functions                                          */
00157 /*---------------------------------------------------------------------------*/
00158 
00159 
00160 /*---------------------------------------------------------------------------*/
00161 /* Definition of static functions                                            */
00162 /*---------------------------------------------------------------------------*/
00163 
00164 
00180 static void
00181 NetworkBuildFormalToActualTableRecursively(
00182   Ntk_Network_t *network,
00183   Hrc_Node_t *hrcNode)
00184 {
00185   st_generator *stGen;
00186   char         *childName;
00187   Hrc_Node_t   *childHrcNode;
00188 
00189   /*
00190    * For each child of the current hnode, process its I/O variables, and
00191    * then recurse on its children.
00192    */
00193   Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) {
00194 
00195     int i;
00196     array_t *childFormalInputs  = Hrc_NodeReadFormalInputs(childHrcNode);
00197     array_t *childFormalOutputs = Hrc_NodeReadFormalOutputs(childHrcNode);
00198     array_t *childFormalIoArray = LocalArrayJoin(childFormalInputs, childFormalOutputs);
00199 
00200     array_t *childActualInputs  = Hrc_NodeReadActualInputs(childHrcNode);
00201     array_t *childActualOutputs = Hrc_NodeReadActualOutputs(childHrcNode);
00202     array_t *childActualIoArray = LocalArrayJoin(childActualInputs, childActualOutputs);
00203 
00204 
00205     /*
00206      * For each I/O variable, construct the appropriate hierarchical name for
00207      * the variable in childHrcNode (formalName) and the variable in the
00208      * hrcNode (actualName).  If actualName already has a corresponding
00209      * actual, then use that, otherwise use actualName as is.  Add
00210      * correspondence from formal (formalName) to actual (actualName).
00211      */
00212     for(i = 0 ; i < array_n(childActualIoArray) ; i++) {
00213       Var_Variable_t *actualVar = array_fetch(Var_Variable_t *, childActualIoArray, i);
00214       Var_Variable_t *formalVar = array_fetch(Var_Variable_t *, childFormalIoArray, i);
00215 
00216       char *nodeName   = Hrc_NodeFindHierarchicalName(hrcNode, TRUE);
00217       /* Special case the situation where hrcNode is current node. */
00218       char *actualName = (strcmp(nodeName, ""))
00219           ? util_strcat3(nodeName, ".",
00220                          Var_VariableReadName(actualVar))
00221           : util_strsav(Var_VariableReadName(actualVar));
00222 
00223       char *childNodeName = Hrc_NodeFindHierarchicalName(childHrcNode, TRUE);
00224       char *formalName = util_strcat3(childNodeName, ".",
00225                                       Var_VariableReadName(formalVar));
00226 
00227       /*
00228        * It is correct to call this function with actualName.  We want to
00229        * check if actualVar is itself a formalVar one level up.
00230        */
00231       char *tempName   = Ntk_NetworkReadActualNameFromFormalName(network, actualName);
00232 
00233       FREE(nodeName);
00234       FREE(childNodeName);
00235 
00236       /*
00237        * (tempName != NIL) => this net is a formal in hrcNode
00238        */
00239       if (tempName != NIL(char)) {
00240         FREE(actualName);
00241         actualName = tempName;
00242       }
00243 
00244       /*
00245        * Ntk_NetworkInsertFormalNameToActualName makes copies of the strings
00246        */
00247       Ntk_NetworkInsertFormalNameToActualName(network, formalName, actualName);
00248 
00249       if (tempName == NIL(char)) {
00250         FREE(actualName);
00251       }
00252       FREE(formalName);
00253     }
00254     array_free(childFormalIoArray);
00255     array_free(childActualIoArray);
00256 
00257     /*
00258      * Recurse.
00259      */
00260     NetworkBuildFormalToActualTableRecursively(network, childHrcNode);
00261   }
00262 }
00263 
00264 
00280 static void
00281 NetworkCreateNodesRecursively(
00282   Ntk_Network_t *network,
00283   Hrc_Node_t    *hrcNode)
00284 {
00285   st_generator   *stGen;
00286   Var_Variable_t *var;
00287   Hrc_Latch_t    *latch;
00288   char           *varName;
00289   char           *latchName;
00290   char           *childName;
00291   Hrc_Node_t     *childHrcNode;
00292   char           *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE);
00293   char           *separator = (char *) ((strcmp(path, "")) ? "." : "");
00294 
00295   /*
00296    * The separator is used to handle the special case when hrcNode is the
00297    * current node in the hierarchy.  If it is, we don't want a "." before the
00298    * variable names.
00299    */
00300 
00301   Hrc_NodeForEachVariable(hrcNode, stGen, varName, var) {
00302     char *nodeName = util_strcat3(path, separator, varName);
00303     NodeCreateAsNecessary(network, nodeName, var);
00304     FREE(nodeName);
00305   }
00306 
00307   /*
00308    * Variable for reset is the same as for present state.  Hence, iterating
00309    * through the list of variables gets us just the present state.  Therefore,
00310    * we need to special case the reset (or init) nodes.
00311    */
00312   Hrc_NodeForEachLatch(hrcNode, stGen, latchName, latch) {
00313     char *partialNodeName = util_strcat3(path, separator, latchName);
00314     char *nodeName        = util_strcat3(partialNodeName, "$INIT", "");
00315 
00316     FREE(partialNodeName);
00317     NodeCreateAsNecessary(network, nodeName, Hrc_LatchReadOutput(latch));
00318     FREE(nodeName);
00319   }
00320   FREE(path);
00321 
00322   /* Recurse. */
00323   Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) {
00324     NetworkCreateNodesRecursively(network, childHrcNode);
00325   }
00326 }
00327 
00328 
00340 static void
00341 NodeCreateAsNecessary(
00342   Ntk_Network_t  *network,
00343   char           *nodeName,
00344   Var_Variable_t *var)
00345 {
00346   if (Ntk_NetworkFindNodeByName(network, nodeName)) {
00347     return;
00348   }
00349 
00350   (void) Ntk_NodeCreateInNetwork(network, nodeName, var);
00351 }
00352 
00353 
00380 static boolean
00381 NetworkDeclareNodesRecursively(
00382   Ntk_Network_t *network,
00383   Hrc_Node_t    *hrcNode,
00384   boolean        buildMvfs,
00385   mdd_manager  **mddMgr)
00386 {
00387   int i;
00388   st_generator   *stGen;
00389   char           *latchName;
00390   Var_Variable_t *var;
00391   Hrc_Latch_t    *latch;
00392   Tbl_Table_t    *table;
00393   char           *childName;
00394   Hrc_Node_t     *childHrcNode;
00395   boolean         result = TRUE;
00396   char           *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE);
00397   char           *separator = (char *) ((strcmp(path, "")) ? "." : "");
00398 
00399   /*
00400    * First declare the network's PI/PO nodes.
00401    */
00402   NetworkDeclareIONodes(network, hrcNode);
00403 
00404   /*
00405    * Next, declare those nodes whose function is represented by a table.  Note
00406    * that his iterator does not pick up those tables that define the
00407    * initialization logic of latches.
00408    */
00409   Hrc_NodeForEachNameTable(hrcNode, i, table) {
00410     int index;
00411     Tbl_TableForEachOutputVar(table, index, var) {
00412       boolean     status;
00413       char       *fullVarName = util_strcat3(path, separator,
00414                                                Var_VariableReadName(var));
00415       Ntk_Node_t *node        = Ntk_NetworkFindNodeByName(network, fullVarName);
00416 
00417       FREE(fullVarName);
00418       status = NodeDeclareWithTable(node, table, index, path, buildMvfs, *mddMgr);
00419       if (!status) {
00420         result = FALSE;
00421       }
00422       MddManagerResetIfNecessary(mddMgr);
00423     }
00424   }
00425 
00426   /*
00427    * Declare each latch and its corresponding next state shadow node.
00428    */
00429   NetworkDeclareLatches(network, hrcNode);
00430 
00431   /*
00432    * Declare the "initial" node corresponding to each latch.
00433    */
00434   Hrc_NodeForEachLatch(hrcNode, stGen, latchName, latch) {
00435     int index;
00436 
00437     table = Hrc_LatchReadResetTable(latch);
00438 
00439     /*
00440      * There is only one output variable (the 0th output) for any table
00441      * defining the initial function of a latch, but we use an iterator to get
00442      * the variable for convenience.
00443      */
00444     Tbl_TableForEachOutputVar(table, index, var) {
00445       boolean      status;
00446       char        *fullVarName = util_strcat3(path, separator, Var_VariableReadName(var));
00447       char        *initName    = util_strcat3(fullVarName, "$INIT", "");
00448       Ntk_Node_t  *node        = Ntk_NetworkFindNodeByName(network, initName);
00449 
00450       /*
00451        * Since the output of this table corresponds to a latch PS, can get name
00452        * of the initial node by attaching $INIT.
00453        */
00454       FREE(fullVarName);
00455       FREE(initName);
00456 
00457       status = NodeDeclareWithTable(node, table, index, path, buildMvfs, *mddMgr);
00458       if (!status) {
00459         result = FALSE;
00460       }
00461       MddManagerResetIfNecessary(mddMgr);
00462     }
00463   }
00464   FREE(path);
00465 
00466   /* Recurse. */
00467   Hrc_NodeForEachChild(hrcNode, stGen, childName, childHrcNode) {
00468     boolean status = NetworkDeclareNodesRecursively(network, childHrcNode,
00469                                                     buildMvfs, mddMgr);
00470     if (!status) {
00471       result = FALSE;
00472     }
00473   }
00474 
00475   return result;
00476 }
00477 
00478 
00492 static array_t *
00493 LocalArrayJoin(
00494   array_t *array1,
00495   array_t *array2)
00496 {
00497   if (array_n(array1) == 0) {
00498     return (array_dup(array2));
00499   }
00500   else if (array_n(array2) == 0) {
00501     return (array_dup(array1));
00502   }
00503   else {
00504     return (array_join(array1, array2));
00505   }
00506 }
00507 
00508 
00525 static array_t *
00526 TableCreateFormalInputNameArray(
00527   Tbl_Table_t *table,
00528   char        *namePrefix)
00529 {
00530   int             index;
00531   array_t        *nameArray;
00532   Var_Variable_t *var;
00533   char           *separator = (char *) ((strcmp(namePrefix, "")) ? "." : "");
00534 
00535   /*
00536    * Allocate an array of length equal to the number of inputs of the table.
00537    * Then, for each input, add the full path name of the input to the array.
00538    */
00539   nameArray = array_alloc(char *, Tbl_TableReadNumInputs(table));
00540   Tbl_TableForEachInputVar(table, index, var) {
00541     char *inputFullName = util_strcat3(namePrefix, separator, Var_VariableReadName(var));
00542     array_insert(char *, nameArray, index, inputFullName);
00543   }
00544 
00545   return (nameArray);
00546 }
00547 
00548 
00558 static void
00559 NameArrayFree(
00560   array_t *nameArray)
00561 {
00562   int i;
00563 
00564   for (i = 0; i < array_n(nameArray); i++) {
00565     char *name = array_fetch(char *, nameArray, i);
00566     FREE(name);
00567   }
00568   array_free(nameArray);
00569 }
00570 
00585 static boolean
00586 NetworkAbstractNodes(
00587   Ntk_Network_t *network,
00588   lsList abstractedNames)
00589 {
00590   char  *name;
00591   lsGen gen;
00592 
00593   /*
00594    * For each abstracted name, cut the corresponding net, and introduce a new
00595    * node.
00596    */
00597   lsForEachItem(abstractedNames, gen, name) {
00598     Var_Variable_t *var;
00599     Ntk_Node_t     *abstractNode;
00600     array_t        *abstractNodeFanouts;
00601     int             i;
00602     Ntk_Node_t     *fanout;
00603     char           *abstractNodeName;
00604     Ntk_Node_t     *node = Ntk_NetworkFindNodeByName(network, name);
00605 
00606     /* Make sure the name corresponds to a node in the network. */
00607     if (node == NIL(Ntk_Node_t)) {
00608       error_append("Could not find node corresponding to name: ");
00609       error_append(name);
00610       error_append("\n");
00611       return FALSE;
00612     }
00613 
00614     /* Create the new node in the network as a primary input. */
00615     abstractNodeName = util_strcat3(name, "$ABS", "");
00616     var = Ntk_NodeReadVariable(node);
00617     abstractNode = Ntk_NodeCreateInNetwork(network, abstractNodeName, var);
00618     FREE(abstractNodeName);
00619     Ntk_NodeDeclareAsPrimaryInput(abstractNode);
00620 
00621     /*
00622      * For each fanout y of the node x being abstracted, replace x in y's
00623      * fanin list by the new node, and add y to the fanout list of the new
00624      * node.
00625      */
00626     abstractNodeFanouts = Ntk_NodeReadFanouts(abstractNode);
00627     Ntk_NodeForEachFanout(node, i, fanout) {
00628       int      index        = Ntk_NodeReadFaninIndex(fanout, node);
00629       array_t *fanoutFanins = Ntk_NodeReadFanins(fanout);
00630 
00631       array_insert(Ntk_Node_t *, fanoutFanins, index, abstractNode);
00632       array_insert_last(Ntk_Node_t *, abstractNodeFanouts, fanout);
00633     }
00634 
00635     /*
00636      * Replace the fanout array of the node being abstracted with an empty
00637      * array.
00638      */
00639     array_free(node->fanouts);
00640     node->fanouts = array_alloc(Ntk_Node_t *, 0);
00641   }
00642 
00643   return TRUE;
00644 }
00645 
00646 
00674 static boolean
00675 NodeDeclareWithTable(
00676   Ntk_Node_t  *node,
00677   Tbl_Table_t *table,
00678   int          outIndex,
00679   char        *path,
00680   boolean      buildMvfs,
00681   mdd_manager *mddMgr)
00682 {
00683   Tbl_Table_t *newTable;
00684   int          newOutIndex;
00685   boolean      result   = TRUE;
00686   char        *nodeName = Ntk_NodeReadName(node);
00687 
00688   /*
00689    * If table has no inputs and more than one output, and its output space is
00690    * not complete (i.e. not all output minterms are present, so the outputs
00691    * are correlated), then declare the table a relation.
00692    */
00693   if ((Tbl_TableReadNumInputs(table) == 0)
00694       && (Tbl_TableReadNumOutputs(table) > 1)) {
00695     if (!Tbl_TableTestIsOutputSpaceComplete(table, mddMgr)) {
00696       (void) fprintf(vis_stderr, "Table %s is a relation\n", nodeName);
00697       result = FALSE;
00698     }
00699   }
00700 
00701   if (!buildMvfs) {
00702     newTable = Tbl_TableSoftDup(table);
00703     newOutIndex = outIndex;
00704   }
00705   else {
00706     Mvf_Function_t *outMvf;
00707     int             offset;
00708     int             numInputs     = Tbl_TableReadNumInputs(table);
00709     array_t        *varMap        = array_alloc(int, numInputs);
00710 
00711     outMvf = LocalMvfFunctionForTable(table, outIndex, mddMgr,
00712                                       varMap, &offset);
00713     /*
00714      * If the function is not a non-deterministic constant, or it has some
00715      * inputs, then check that it is deterministic. Always check that it is
00716      * completely specified.
00717      */
00718     if ((numInputs > 0)
00719         || !Mvf_FunctionTestIsNonDeterministicConstant(outMvf)) {
00720       if (!Mvf_FunctionTestIsDeterministic(outMvf)) {
00721         (void) fprintf(vis_stderr, "Table %s is not deterministic\n", nodeName);
00722         result = FALSE;
00723       }
00724     }
00725     if (!Mvf_FunctionTestIsCompletelySpecified(outMvf)) {
00726       (void) fprintf(vis_stderr, "Table %s is not completely specified\n", nodeName);
00727       result = FALSE;
00728     }
00729 
00730     /*
00731      * Build the reduced table for the output corresponding to outIndex.  The
00732      * reduced table will have only one output column (column 0), and will have
00733      * only those input columns corresponding to the variables appearing in the
00734      * support of outMvf.
00735      */
00736     newTable = Tbl_TableCreateTrueSupportTableForOutput(table, outMvf, mddMgr,
00737                                                         offset, outIndex,
00738                                                         varMap);
00739     newOutIndex = 0;
00740     array_free(varMap);
00741     Mvf_FunctionFree(outMvf);
00742   }
00743 
00744 
00745   /*
00746    * Declare the node with the reduced table.
00747    */
00748   if (Tbl_TableTestIsNonDeterministicConstant(newTable, newOutIndex)) {
00749     Ntk_NodeDeclareAsPseudoInput(node, newTable, newOutIndex);
00750   }
00751   else {
00752     array_t *formalInputNameArray = TableCreateFormalInputNameArray(newTable, path);
00753 
00754     /* Ntk_NodeDeclareAsCombinational will test for constants. */
00755     Ntk_NodeDeclareAsCombinational(node, newTable, formalInputNameArray, newOutIndex);
00756     NameArrayFree(formalInputNameArray);
00757   }
00758 
00759   return result;
00760 }
00761 
00762 
00775 static void
00776 NetworkDeclareIONodes(
00777   Ntk_Network_t *network,
00778   Hrc_Node_t    *hrcNode)
00779 {
00780   st_generator   *stGen;
00781   char           *varName;
00782   Var_Variable_t *var;
00783   char           *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE);
00784   char           *separator = (char *) ((strcmp(path, "")) ? "." : "");
00785 
00786   Hrc_NodeForEachVariable(hrcNode, stGen, varName, var) {
00787     if (Var_VariableTestIsPO(var) || Var_VariableTestIsPI(var)) {
00788       char *fullVarName = util_strcat3(path, separator, Var_VariableReadName(var));
00789       char *tmpName     = Ntk_NetworkReadActualNameFromFormalName(network, fullVarName);
00790 
00791       /*
00792        * If tmpName == NIL, this must be a PI/PO of the top most node in the hierarchy of
00793        * nodes. Hence, this is a true input/output of the hierarchy.
00794        */
00795       if (tmpName == NIL(char)) {
00796         Ntk_Node_t *node = Ntk_NetworkFindNodeByName(network, fullVarName);
00797         if (Var_VariableTestIsPO(var)) {
00798           Ntk_NodeDeclareAsPrimaryOutput(node);
00799         }
00800         else {
00801           Ntk_NodeDeclareAsPrimaryInput(node);
00802         }
00803       }
00804       FREE(fullVarName);
00805     }
00806   }
00807   FREE(path);
00808 }
00809 
00810 
00822 static void
00823 NetworkDeclareLatches(
00824   Ntk_Network_t *network,
00825   Hrc_Node_t    *hrcNode)
00826 {
00827   st_generator   *stGen;
00828   char           *name;
00829   Hrc_Latch_t    *latch;
00830   char           *path = Hrc_NodeFindHierarchicalName(hrcNode, TRUE);
00831   char           *separator = (char *) ((strcmp(path, "")) ? "." : "");
00832 
00833   Hrc_NodeForEachLatch(hrcNode, stGen, name, latch) {
00834     char       *nextStateName;
00835     Ntk_Node_t *nextStateNode;
00836     char       *latchName = util_strcat3(path, separator,
00837                              Var_VariableReadName(Hrc_LatchReadOutput(latch)));
00838     char       *initName  = util_strcat3(latchName, "$INIT", "");
00839     char       *dataName  = util_strcat3(path, separator,
00840                              Var_VariableReadName(Hrc_LatchReadInput(latch)));
00841     Ntk_Node_t *latchNode = Ntk_NetworkFindNodeByName(network, latchName);
00842 
00843     FREE(latchName);
00844     Ntk_NodeDeclareAsLatch(latchNode, dataName, initName);
00845     FREE(initName);
00846     FREE(dataName);
00847 
00848     /*
00849      * Create the corresponding shadow next state node for the latch.  This holds
00850      * the next state variable.
00851      */
00852     nextStateName = util_strcat3(Ntk_NodeReadName(latchNode), "$NS", "");
00853     nextStateNode = Ntk_NodeCreateInNetwork(network, nextStateName,
00854                                             Hrc_LatchReadOutput(latch));
00855     FREE(nextStateName);
00856     Ntk_NodeDeclareAsShadow(nextStateNode, latchNode);
00857   }
00858   FREE(path);
00859 }
00860 
00861 
00876 static void
00877 MddManagerResetIfNecessary(
00878   mdd_manager **mddMgr)
00879 {
00880   if (bdd_num_vars(*mddMgr) > MAX_NUMBER_BDD_VARS) {
00881     mdd_quit(*mddMgr);
00882     *mddMgr = mdd_init_empty();
00883     bdd_dynamic_reordering(*mddMgr, BDD_REORDER_SIFT, BDD_REORDER_VERBOSITY_DEFAULT);
00884   }
00885 }
00886 
00887 
00900 static Mvf_Function_t *
00901 LocalMvfFunctionForTable(
00902   Tbl_Table_t *table,
00903   int outIndex,
00904   mdd_manager *mddMgr,
00905   array_t *varMap,
00906   int *offsetPtr
00907   )
00908 {
00909   Mvf_Function_t *outMvf;
00910   Var_Variable_t *var;
00911   int             colNum;
00912   int             offset;
00913   int             i;
00914   int             numInputs     = Tbl_TableReadNumInputs(table);
00915   array_t        *faninMvfArray = array_alloc(Mvf_Function_t *, numInputs);
00916   array_t        *mvarValues    = array_alloc(int, numInputs);
00917   st_table       *varTable      = st_init_table(st_ptrcmp,st_ptrhash);
00918 
00919   /* Create MDD variables for the table inputs.  If there are more inputs
00920    * tied to the sameVar_Variable_t, create just one MDD variable.  Record
00921    * the mapping from inputs to variable indices in varMap.
00922    */
00923   Tbl_TableForEachInputVar(table, colNum, var) {
00924     int index;
00925     if (st_lookup_int(varTable,var,&index)) {
00926       array_insert_last(int, varMap, index);
00927     } else {
00928       index = array_n(mvarValues);
00929       array_insert_last(int, varMap, index);
00930       st_insert(varTable, var, (char *) (long) index);
00931       array_insert_last(int, mvarValues, Var_VariableReadNumValues(var));
00932     }
00933   }
00934   st_free_table(varTable);
00935 
00936   /* Restarting the manager is optional.  The effect is to get rid of the
00937    * MDD variable information in the manager, without incurring the cost
00938    * of quitting and re-initializing the manager. */
00939   mdd_restart(mddMgr);
00940   offset = array_n(mdd_ret_mvar_list(mddMgr));  /* number of existing mvars */
00941   assert(offset == 0);
00942   mdd_create_variables(mddMgr, mvarValues, NIL(array_t), NIL(array_t));
00943   array_free(mvarValues);
00944 
00945   /*
00946    * Construct an MVF for each table input. The MVF for column i is the MVF
00947    * for MDD variable i.
00948    */
00949   for (i = 0; i < numInputs; i++) {
00950     int index = array_fetch(int, varMap, i);
00951     Mvf_Function_t *faninMvf = Mvf_FunctionCreateFromVariable(mddMgr, (index + offset));
00952     array_insert_last(Mvf_Function_t *, faninMvfArray, faninMvf);
00953   }
00954 
00955   /* Compute the MVF of the output indexed by outIndex. */
00956   outMvf = Tbl_TableBuildMvfFromFanins(table, outIndex, faninMvfArray, mddMgr);
00957   Mvf_FunctionArrayFree(faninMvfArray);
00958 
00959   *offsetPtr = offset;
00960   return outMvf;
00961 
00962 } /* LocalMvfFunctionForTable */