source: vis_dev/vis-2.3/src/fsm/fsmReach.c @ 45

Last change on this file since 45 was 15, checked in by cecile, 13 years ago

Vis main file for expermeriments

File size: 80.8 KB
Line 
1/**CFile***********************************************************************
2
3  FileName    [fsmReach.c]
4
5  PackageName [fsm]
6
7  Synopsis    [Routines to perform reachability on the FSM structure.]
8
9  Author      [Rajeev K. Ranjan, In-Ho Moon, Kavita Ravi]
10
11  Copyright   [Copyright (c) 1994-1996 The Regents of the Univ. of California.
12  All rights reserved.
13
14  Permission is hereby granted, without written agreement and without license
15  or royalty fees, to use, copy, modify, and distribute this software and its
16  documentation for any purpose, provided that the above copyright notice and
17  the following two paragraphs appear in all copies of this software.
18
19  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
20  DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
21  OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
22  CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
25  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
26  FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN
27  "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
28  MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.]
29
30******************************************************************************/
31
32#include "fsmInt.h"
33#include "bdd.h"
34#include "ntm.h"
35#include "img.h"
36#include "sim.h"
37
38static char rcsid[] UNUSED = "$Id: fsmReach.c,v 1.102 2009/04/11 01:40:54 fabio Exp $";
39
40/*---------------------------------------------------------------------------*/
41/* Constant declarations                                                     */
42/*---------------------------------------------------------------------------*/
43/* HD constants */
44#define FSM_HD_NONGREEDY 0 /* flag to indicate non-greedy computation at
45                              dead-ends */
46#define FSM_HD_GREEDY 1 /* flag to indicate greedy computation at dead-ends */
47#define FSM_HD_LARGE_SIZE 100000 /* size considered large for reached */
48#define FSM_HD_MID_SIZE 50000    /* size considered medium for reached*/
49#define FSM_HD_MINT_GROWTH 0.5   /* factor measuring minterm jump of reached*/
50#define FSM_HD_GROWTH_RATE 0.04 /* Growth rate for reached in measuring slow
51                                 * growth. */
52#define FSM_MDD_DONT_FREE 0  /* flag to indicate that bdd should not be freed. */
53#define FSM_MDD_FREE 1       /* flag to indicate that bdd should be freed.*/
54#define FSM_HD_NUM_SLOW_GROWTHS 5 /* number of iterations of allowed
55                                   * slow growth of reached. */
56/*---------------------------------------------------------------------------*/
57/* Structure declarations                                                    */
58/*---------------------------------------------------------------------------*/
59
60/**AutomaticStart*************************************************************/
61
62/*---------------------------------------------------------------------------*/
63/* Static function prototypes                                                */
64/*---------------------------------------------------------------------------*/
65
66static int CheckImageValidity(mdd_manager *mddManager, mdd_t *image, array_t *domainVarMddIdArray, array_t *quantifyVarMddIdArray);
67/*static*/ int ComputeNumberOfBinaryStateVariables(mdd_manager *mddManager, array_t *mddIdArray);
68static mdd_t * AddStates(mdd_t *a, mdd_t *b, int freeA, int freeB);
69static void RandomSimulation(int simNVec, Fsm_Fsm_t *fsm, Fsm_RchType_t approxFlag, mdd_t *initialStates, mdd_t **reachableStates, mdd_t **fromLowerBound, FsmHdStruct_t *hdInfo);
70static void PrintStatsPerIteration(Fsm_RchType_t approxFlag, int nvars, int depth, FsmHdStruct_t *hdInfo, mdd_manager *mddManager, mdd_t *reachableStates, mdd_t *fromLowerBound, array_t *mintermVarArray);
71static void HdInduceFullDeadEndIfNecessary(mdd_manager *mddManager, Img_ImageInfo_t *imageInfo, mdd_t **fromLowerBound, mdd_t **fromUpperBound, mdd_t **reachableStates, mdd_t **image, FsmHdStruct_t *hdInfo, int *depth, int shellFlag, array_t *onionRings, array_t *mintermVarArray, int oldSize, double oldMint, int verbosityLevel);
72static mdd_t * ComputeInitialStates(Fsm_Fsm_t *fsm, int shellFlag, boolean printWarning);
73static int CheckStatesContainedInInvariant(mdd_t *reachableStates, array_t *invarStates);
74static void HdComputeReachabilityParameters(mdd_manager *mddManager, Img_ImageInfo_t *imageInfo, mdd_t **reachableStates, mdd_t **fromUpperBound, mdd_t **fromLowerBound, mdd_t **image, FsmHdStruct_t *hdInfo, mdd_t *initialStates, array_t *mintermVarArray, int *depth, int printStep, int shellFlag, array_t *onionRings, int verbosityLevel);
75static int InitializeIncrementalParameters(Fsm_Fsm_t *fsm, Ntk_Network_t *network, array_t **arrayOfRoots, st_table **tableOfLeaves);
76static mdd_t * IncrementalImageCompute(Ntk_Network_t *network, Fsm_Fsm_t *fsm, mdd_manager *mddManager, mdd_t *fromLowerBound, mdd_t *fromUpperBound, mdd_t *toCareSet, array_t *arrayOfRoots, st_table *tableOfLeaves, array_t *smoothVarArray, array_t *relationArray, int numLatch);
77static void PrintOnionRings(Fsm_Fsm_t *fsm, int printStep, Fsm_RchType_t approxFlag, int nvars);
78static array_t * GenerateGuidedSearchSequenceArray(array_t *guideArray);
79static void ComputeReachabilityParameters(mdd_manager *mddManager, Img_ImageInfo_t *imageInfo, Fsm_RchType_t approxFlag, mdd_t **reachableStates, mdd_t **fromUpperBound, mdd_t **fromLowerBound, mdd_t **image, FsmHdStruct_t *hdInfo, mdd_t *initialStates, array_t *mintermVarArray, int *depth, int printStep, int shellFlag, array_t *onionRings, int verbosityLevel, boolean guidedSearchMode, mdd_t *hint, int *hintDepth, boolean *notConverged);
80
81/**AutomaticEnd***************************************************************/
82
83
84/*---------------------------------------------------------------------------*/
85/* Definition of exported functions                                          */
86/*---------------------------------------------------------------------------*/
87/**Function********************************************************************
88
89  Synopsis [Computes the set of reachable states of an FSM.]
90
91  Description [Computes the set of reachable states of an FSM.  If
92  this set has already been computed, then just returns the result of
93  the previous computation. The recomputation is done anyway if onion
94  rings are required and have not been previously computed. The
95  calling application is responsible for freeing the returned MDD in
96  all cases.  If verbosityLevel is greater than 1, then information is
97  printed after every k steps of reachability, where k is defined by
98  the -s option in the compute_reach command (the default for k is
99  1). If reorderFlag is set, then dynamic reordering is invoked once
100  when the size of the reachable state set reaches the threshold given
101  by reorderThreshold.  This is independent of the
102  dynamic_variable_reordering command. The shell flag indicates that
103  the onion rings of frontier states should be stored. The default
104  does not store the onion rings. The default value for approxFlag is
105  Fsm_Rch_Default_c. See fsm.h for values.
106
107  The procedure offers the following variations of reachability
108  analysis: 1. Exact Reachability analysis by breadth-first search
109  (default). 2. Reachability Analysis (HD) . 3. Reachability Analysis
110  (upper bound by overapproximate FSM traversal). 4 ARDC-accelerated
111  Reachability Analysis.  5. Invariant checking with early termination.
112
113  A lower bound (specified by depthValue) on the reachable states may
114  be obtained by performing a specified number of iterations
115  (depthValue argument). It updates a field in the
116  fsm.reachabilityInfo signalling that the reachable states are an
117  under approximation. The default for the depthValue argument is 0
118  which indicates that reachability analysis computation should
119  proceed to a fixpoint. If a depthValue is specified after the
120  computation of reachable states, the reachable states is returned,
121  else depthValue number of computations are performed. Every non-zero
122  depthValue is interpreted as the number of iterations (image
123  computations) to be performed from the current state (not from the
124  initial state).
125
126  Reachability Analysis (HD) is requested as approxFlag =  Fsm_Rch_Hd_c.
127  HD provides an exact set of reachable states with memory efficiency or
128  a lower bound if reachability analysis does not complete.
129  HD Principles: 1. compute image of small BDDs. 2. compute partial
130  image if necessary 3. When no new states are generated (dead-end),
131  compute new states from image of reached in a decomposed form.  Allow
132  no partial image.  4. When there is a big jump in the size of
133  reached, compute its entire image.  5. store states that will
134  produce no new successors (interior states)
135
136  The algorithm is implemented as follows
137  from = init; reached = init;
138  while (reached != 1 && from != 0) {
139    Allow partial image;
140    image = Image(from);
141    Check if partial image;
142    from = image - reached;
143    if (!partial image) interior_states_candidate = from;
144    if (from == 0 || slow growth of Reached for 5 iterations) {
145      Dead-end computation(greedy): find new states from image of reached;
146    }
147    if (from != 0 and (reached+from) size has a big jump) {
148      Dead-end computation(non-greedy): find the entire image of reached;
149    }
150    if (from != 0) {
151      Compute dense subset of from with at least 1 new state;
152      if subset contains from (i.e., all new states)
153                       interior states += interior states candidate;
154      reached = reached + from/subset;
155    }
156  }
157
158  Legend:  fromLowerBound = from; initialStates = init;
159           reachableStates = reached
160           fromUpperBound = reachableStates (BFS)/fromLowerBound(HD)
161           interiorStates = states with no new successors
162           interiorStateCandidates = states that may be interior
163                  states depending on whether all of them are added to
164                  reachableStates.
165
166  Currently, this does not support the incrementalFlag = 1 option.
167
168  Reachability Analysis (upper bound by overapproximate FSM traversal)
169  gives an upper bound of exact reachable states by overapproximation.
170  It is requested as approxFlag = Fsm_Rch_Oa_c. To do this, first, it
171  groups latch variables by using SSD(State Space Decomposition in the
172  paper Cho et.al, TCAD96-DEC) algorithm, then computes the reachable
173  states of each submachines until convergence, then the product of
174  reachable states of all submachines is an overapproximate reachable
175  states. In this case, depthValue and shellFlag and incrementalFlag
176  are incompatible with this option.
177
178  ARDC-accelerated Reachability Analysis may allow faster and smaller
179  memory usage reachability analysis. First, it computes
180  overapproximated reachable states (if already computed, just use it).
181  Reachability Analysis is then performed (any value of approxFlag is
182  applicable) with a transition relation minimized with the complement
183  of overapproximate reachable states as don't cares (called
184  ARDC). This option is requested as ardc = 1.
185
186  invarStates is a set of invariant states that can be specified. The
187  reachable states must satisfy all invariants. The default value is
188  NULL. Any invalid invariant must also be set to NULL in the
189  invarStaes array. This option is used by the check_invariant
190  command. When an array of invariant states is provided, reachability
191  analysis is done until an invariant is violated or when reachability
192  finishes, whichever is earlier. If an approximation of the reachable
193  states exists, then each invariant is checked for violation. If none
194  are violated, the set of reachable states is returned. It is the
195  caller's resposibility to remove the violating invariant from the
196  invarStates array to continue checking the remaining
197  invariants. The presence of invarStates takes precedence over a
198  non-zero depthValue.
199
200  In general, the reachable states may not be consistent with the
201  onion rings i.e., sum of onion rings is always contained in the
202  reachable states.  When the shell flag is specified and onion rings
203  exist, the initial states are set to the sum of the onion ring
204  states instead of the default initial states of the fsm or
205  previously computed reachable states.
206
207  Some random simulation of the reachable states can be done prior to
208  reachability analysis. This is turned on using the rch_simulate
209  flag. A number should be specifed in the command : set sim_reach
210  <number>, which specifies the number of vectors to be simulated.
211  The initial states are then set to the simulated set of states. If
212  HD is specified, a subset may be taken.
213
214  The recompute flag asks for an explicit recomputation. This means
215  that even reachable states have been computed, they will be
216  recomputed.
217
218  On consecutive calls, recomputation is avoided as much as
219  possible. The specific cases are when
220  Case a. No shell Flag: Recomputation is avoided when reachability is
221  done, when an underapproximation exists and it violates an
222  invariant,  an overapproximation exists and all invariants pass.
223
224  Case b. With shell flag: Recomputation is avoided when onion rings
225  are up-to-date and reachability is done or when onion rings are
226  up-to-date, an underapproximation exists and an invariant fails.
227
228  Update of fsm.reachabiltiyInfo fields are also based on minimum
229  recomputation. The reachability field is updated only if the current
230  set of reachable states are larger than the previous set.
231
232  printWarning flag turns is used to turn on/off the warning message
233  printed when the previously computed reachable states are used to
234  proceed with computation. The default is TRUE.  ]
235
236  SideEffects [The result of the reachable state computation is stored
237  with the FSM. i.e., depth, reachable set, underapprox flag. ]
238
239  SeeAlso [Fsm_FsmComputeInitialStates
240  Fsm_ArdcComputeOverApproximateReachableStates]
241
242******************************************************************************/
243mdd_t *
244Fsm_FsmComputeReachableStates(
245  Fsm_Fsm_t *fsm,
246  int incrementalFlag,
247  int verbosityLevel,
248  int printStep,
249  int depthValue,
250  int shellFlag,
251  int reorderFlag,
252  int reorderThreshold,
253  Fsm_RchType_t approxFlag,
254  int ardc,
255  int recompute,
256  array_t *invarStates,
257  boolean printWarning,
258  array_t *guideArray)
259{
260  /* BFS variables */
261  Img_ImageInfo_t *imageInfo = NIL(Img_ImageInfo_t); /* image info structure*/
262  Img_ImageInfo_t *oldImageInfo = NIL(Img_ImageInfo_t);
263  mdd_t           *reachableStates;/* reachable states */
264  mdd_t           *unreachableStates;
265  mdd_t           *fromLowerBound; /* new states in each iteration */
266  mdd_t           *fromUpperBound; /* set to reachable states */
267  mdd_t           *image, *newImage;/* image computed at each iteration */
268  mdd_t           *initialStates;  /* initial states */
269  mdd_t           *toCareSet;      /* the complement of the reached set */
270  int              depth = 0;      /* depth upto which the computation is
271                                    * performed.
272                                    */
273  graph_t         *partition, *oldPartition;
274  mdd_manager     *mddManager = Fsm_FsmReadMddManager(fsm); /* mdd manager */
275  Ntk_Network_t   *network = fsm->network; /* network */
276  bdd_reorder_type_t currentMethod =
277    Ntk_NetworkReadDynamicVarOrderingMethod(network); /* current reordering
278                                                       * method */
279  int firstTimeFlag = TRUE, firstReorderFlag = FALSE;
280                         /* a flag to indicate the start of the computation */
281  Fsm_RchStatus_t rchStatus = Fsm_Rch_Under_c;
282                         /* under approximation of the reached set computed */
283  int reachableStateSetSize; /* bdd size of the reached set */
284  array_t *mintermVarArray; /* array of present state variables */
285  array_t *onionRings = NIL(array_t);
286                            /* onionringarray for shellFlag computation */
287
288  /* Incremental flag  variables */
289  array_t *arrayOfRoots = NIL(array_t);
290  st_table *tableOfLeaves = NIL(st_table);
291  int numLatch = 0;
292  array_t *relationArray = NIL(array_t), *smoothVarArray = NIL(array_t);
293
294  boolean notConverged = FALSE; /* flag that says that the fixpoint procedure
295                                   did not converge. */
296  /* HD variables */
297  FsmHdStruct_t *hdInfo = NULL;
298  int nvars;       /* number of present state variables */
299
300
301  /* Simulation variables */
302  int simNVec = 0;                 /* number of simulation vectors. */
303  char *simString = Cmd_FlagReadByName("rch_simulate");
304
305  /* Guided Search */
306  array_t *hintDepthArray = NIL(array_t);
307  int hintDepth = -1;
308  mdd_t   *hint = NIL(mdd_t); /* iterates over guide array */
309  int      hintnr;            /* idem                      */
310  boolean guidedSearchMode = FALSE;
311  boolean guideArrayAllocated = FALSE;
312
313  boolean invariantFailed = FALSE;
314
315  /* initializations */
316  /* if fsm is a submachine, takes realPsVars to count minterm correctly. */
317  mintermVarArray = Fsm_FsmReadPresentStateVars(fsm);
318
319  /* compute number of present state variables */
320  nvars = ComputeNumberOfBinaryStateVariables(mddManager, mintermVarArray);
321  assert(nvars > 0);
322
323  /* initializations */
324  if (recompute) {
325    if (incrementalFlag &&
326        ((approxFlag == Fsm_Rch_Hd_c) || (approxFlag == Fsm_Rch_Oa_c))) {
327      fprintf(vis_stdout,
328              "** rch error: Incremental flag and HD computation are not compatible\n");
329      return NIL(mdd_t);
330    }
331    FsmResetReachabilityFields(fsm, approxFlag);
332  } else if ((!shellFlag) || Fsm_FsmTestReachabilityOnionRingsUpToDate(fsm)) {
333    /* If already computed and exact , just return a copy. */
334    reachableStates = Fsm_FsmReadReachableStates(fsm);
335    if (reachableStates != NIL(mdd_t)){
336      if (printWarning) {
337        fprintf(vis_stdout, "** rch info: Reachable states have been previously computed.\n");
338        fprintf(vis_stdout, "** rch info: Not recomputing reachable states.\n");
339        fprintf(vis_stdout, "** rch info: Use compute_reach -F to recompute if necessary.\n");
340      }
341      if (!shellFlag) {
342        if (printWarning) {
343          if (FsmReadReachabilityComputationMode(fsm) == Fsm_Rch_Bfs_c) {
344            fprintf(vis_stdout, "** rch info: All previous computations done using BFS (-A 0 option).\n");
345          } else {
346            fprintf(vis_stdout, "** rch info: Some previous computations done using BFS/DFS mode (-A 1 or -g option).\n");
347          }
348        }
349        return (mdd_dup(reachableStates));
350      } else if (Fsm_FsmReadReachabilityOnionRings(fsm)) {
351        /* if onion rings exist, since they are up-to-date, return the
352         * reachable states
353         */
354        if (printWarning) {
355          if (Fsm_FsmReadReachabilityOnionRingsMode(fsm) == Fsm_Rch_Bfs_c) {
356            fprintf(vis_stdout, "** rch info: Onion rings have been computed using BFS (-A 0 option)\n");
357          } else {
358            fprintf(vis_stdout, "** rch info: Some onion rings have been computed using BFS/DFS (-A 1 or -g option)\n");
359          }
360        }
361        if (printStep)
362          PrintOnionRings(fsm, printStep, approxFlag, nvars);
363        return (mdd_dup(reachableStates));
364      }
365    }
366
367    /* if some computed states exist and they violate an invariant,
368       return the current set of reachable states */
369    reachableStates = Fsm_FsmReadCurrentReachableStates(fsm);
370    if (reachableStates != NIL(mdd_t)) {
371      if (!shellFlag) {
372        /* if an underApprox  exists, check invariant, if any */
373        if (invarStates != NIL(array_t)) {
374          if (!CheckStatesContainedInInvariant(reachableStates, invarStates)) {
375            if (printWarning) {
376              fprintf(vis_stdout, "** rch info: Invariant violation using previously computed states\n");
377            }
378            /* return violating reachable states */
379            return (mdd_dup(reachableStates));
380          }
381        }
382      } else if (Fsm_FsmReadReachabilityOnionRings(fsm)) {
383        /* an invariant fails. */
384        if (invarStates != NIL(array_t)) {
385          if (!CheckStatesContainedInInvariant(reachableStates, invarStates)) {
386            if (printWarning) {
387              fprintf(vis_stdout, "** rch info: Invariant violation using previously computed states\n");
388              if (Fsm_FsmReadReachabilityOnionRingsMode(fsm) == Fsm_Rch_Bfs_c) {
389                fprintf(vis_stdout, "** rch info: Previous onion rings computed in BFS (-A 0 option).\n");
390              } else {
391                fprintf(vis_stdout, "** rch info: Some set of onion rings have been computed using BFS/DFS (-A 1 or -g option)\n");
392              }
393              fprintf(vis_stdout, "** rch info: Use compute_reach -F to recompute if necessary.\n");
394            }
395            if (printStep) {
396              PrintOnionRings(fsm, printStep, approxFlag, nvars);
397            }
398            return (mdd_dup(reachableStates));
399          }
400        }
401      }
402    }
403    /* if an over approx exists, check invariant, if any */
404    if ((invarStates != NIL(array_t)) && (!shellFlag) && (!depthValue) &&
405        (Fsm_FsmReadOverApproximateReachableStates(fsm)
406         != NIL(array_t))) {
407      if (FsmArdcCheckInvariant(fsm, invarStates)) {
408        fprintf(vis_stdout, "** rch info: Over approximation exists, using over approximation for invariant checking.\n");
409         return(Fsm_ArdcGetMddOfOverApproximateReachableStates(fsm));
410      }
411    }
412
413    if (incrementalFlag &&
414        ((approxFlag == Fsm_Rch_Hd_c) || (approxFlag == Fsm_Rch_Oa_c))) {
415      fprintf(vis_stdout,
416              "** rch error: Incremental flag and HD computation are not compatible\n");
417
418      return NIL(mdd_t);
419    }
420  }
421  /* onion rings make no sense with Over approx */
422  if (shellFlag && (approxFlag == Fsm_Rch_Oa_c)) {
423    fprintf(vis_stdout, "** rch error: Can't generate onion rings with over approx\n");
424    return NIL(mdd_t);
425  }
426
427  /* depth value makes no sense with over approximation */
428  if (depthValue && (approxFlag == Fsm_Rch_Oa_c)) {
429    fprintf(vis_stdout, "** rch error: Can't generate over approx with depth Value\n");
430    return NIL(mdd_t);
431  }
432
433  /* guided search cannot be done with Over approximation */
434  if ((guideArray != NIL(array_t)) && (approxFlag == Fsm_Rch_Oa_c)) {
435    fprintf(vis_stdout, "Guided search is not implemented with Over approximations\n");
436    return NIL(mdd_t);
437  }
438
439  /* initializations */
440  reachableStateSetSize = 0;
441  if ((approxFlag == Fsm_Rch_Hd_c) || (guideArray != NIL(array_t))) {
442    /* this structure is needed for HD and guidedSearch */
443    hdInfo = FsmHdStructAlloc(nvars);
444  }
445
446  simNVec = 0;
447  if (simString != NIL(char)) {
448    simNVec = strtol(simString, NULL, 10);
449    if (simNVec <= 0)  simNVec = 0;
450  }
451  /* initialize onion ring array */
452  if (shellFlag) {
453    if (Fsm_FsmReadReachabilityOnionRings(fsm) == NIL(array_t)) {
454      onionRings = array_alloc(mdd_t *, 0);
455    } else {
456      onionRings = Fsm_FsmReadReachabilityOnionRings(fsm);
457    }
458  }
459
460  /* Computes ARDCs, and  overapproximation by SSD traversal, if required. */
461  if (approxFlag == Fsm_Rch_Oa_c || ardc) {
462    long initialTime = 0;
463    long finalTime;
464
465    assert(!incrementalFlag);
466
467    if (verbosityLevel > 0)
468      initialTime = util_cpu_time();
469
470    (void)Fsm_FsmComputeOverApproximateReachableStates(fsm, incrementalFlag,
471        verbosityLevel, printStep, depthValue, shellFlag, reorderFlag,
472        reorderThreshold, recompute);
473
474    if (approxFlag == Fsm_Rch_Oa_c) {
475      if (hdInfo != NIL(FsmHdStruct_t)) FsmHdStructFree(hdInfo);
476      return(Fsm_ArdcGetMddOfOverApproximateReachableStates(fsm));
477    }
478
479    if (verbosityLevel > 0) {
480      finalTime = util_cpu_time();
481      Fsm_ArdcPrintReachabilityResults(fsm, finalTime-initialTime);
482    }
483  }
484
485  if(Cmd_FlagReadByName("linear_compute_range")) {
486    partition = Part_NetworkCreatePartition(network, 0, "temp", (lsList)0,
487        (lsList)0, NIL(mdd_t), Part_Fine_c, 0, 0, 0, 0);
488    oldPartition = fsm->partition;
489    oldImageInfo = fsm->imageInfo;
490    fsm->imageInfo = 0;
491    imageInfo = Fsm_FsmReadOrCreateImageInfoForComputingRange(fsm, 0, 1);
492    unreachableStates = Img_ImageGetUnreachableStates(imageInfo);
493    fprintf(vis_stdout, "%-20s%10g\n", "reachable states =",
494                     mdd_count_onset(mddManager, unreachableStates,
495                                     fsm->fsmData.presentStateVars));
496    fflush(vis_stdout);
497    /* get unreachable states */
498    Img_ImageInfoFree(imageInfo);
499    fsm->imageInfo = oldImageInfo;
500    fsm->partition = oldPartition;
501    Part_PartitionFree(partition);
502    exit(0);
503  }
504  /* Compute the set of initial states. Start with the
505   * underapproximation of Reached states if it exists or sum of
506   * onion rings if shell flag is specified or the initial states of
507   * the fsm.
508   */
509  initialStates = ComputeInitialStates(fsm, shellFlag, printWarning);
510  if (initialStates == NIL(mdd_t)) {
511    fprintf(vis_stdout, "** rch error: No initial states computed.");
512    fprintf(vis_stdout, " No reachability will be performed.\n");
513    if (hdInfo != NIL(FsmHdStruct_t)) FsmHdStructFree(hdInfo);
514    return NIL(mdd_t);
515  }
516
517  if (incrementalFlag){
518    /* Note: if incrementalflag is set, no imageinfo is created! */
519    numLatch = InitializeIncrementalParameters(fsm, network, &arrayOfRoots,
520                                               &tableOfLeaves);
521    smoothVarArray = array_join(fsm->fsmData.presentStateVars,
522                                fsm->fsmData.inputVars);
523    relationArray = array_alloc(mdd_t *, numLatch+1);
524  } else {
525    /* Create an imageInfo for image computations, if not already created. */
526    imageInfo = Fsm_FsmReadOrCreateImageInfo(fsm, 0, 1);
527    if (ardc) {
528      Fsm_ArdcMinimizeTransitionRelation(fsm, Img_Forward_c);
529    }
530  }
531
532  /* Get approximate traversal options */
533  if ((!incrementalFlag) && (approxFlag == Fsm_Rch_Hd_c)) {
534    /* only partial image allowed. No approximation of frontier set */
535    hdInfo->onlyPartialImage =  Fsm_FsmHdOptionReadOnlyPartialImage(hdInfo->options);
536    /* states which can produce no new successors. */
537    hdInfo->interiorStates = bdd_zero(mddManager);
538  }
539
540  /* pertaining to simulation */
541  if (simNVec > 0) {
542    RandomSimulation(simNVec, fsm, approxFlag, initialStates,
543                     &reachableStates, &fromLowerBound, hdInfo);
544  } else {
545    /* start reached set with initial states */
546    reachableStates = mdd_dup(initialStates);
547    fromLowerBound = mdd_dup(reachableStates);
548  }
549
550  /* initialize variables to print */
551  if ((!incrementalFlag) && (approxFlag == Fsm_Rch_Hd_c)) {
552
553    FsmHdStatsComputeSizeAndMinterms(mddManager, reachableStates,
554                           mintermVarArray, nvars,
555                           Fsm_Hd_Reached, hdInfo->stats);
556    FsmHdStatsComputeSizeAndMinterms(mddManager, fromLowerBound,
557                           mintermVarArray, nvars,
558                           Fsm_Hd_From, hdInfo->stats);
559    FsmHdStatsSetMintermFromSubset(hdInfo->stats, FsmHdStatsReadMintermFrom(hdInfo->stats));
560    FsmHdStatsSetSizeFromSubset(hdInfo->stats, FsmHdStatsReadSizeFrom(hdInfo->stats));
561  }
562
563  if (printStep && ((depth % printStep) == 0) && (approxFlag == Fsm_Rch_Hd_c)){
564    fprintf(vis_stdout, "\nIndex: R = Reached; I = Image, F = Frontier, FA = Approximation of Frontier\n");
565    fprintf(vis_stdout, "       f = Minterms in f; |f| = Bdd nodes in f\n\n");
566  }
567  /* initialize for the first iteration */
568   fromUpperBound = reachableStates;
569
570  /* hint array */
571  if (guideArray == NIL(array_t)) {
572    guideArray = array_alloc(mdd_t *, 0);
573    guideArrayAllocated = TRUE;
574  }
575  /* pad with 1 when no hints are provided */
576  if (array_n(guideArray) == 0) {
577    array_insert_last(mdd_t *, guideArray, bdd_one(mddManager));
578  }
579  /* depth sequence for hints. 1-to-1 correspondence with guidearray */
580  /* -1 implies apply hint to convergence. */
581  hintDepthArray = GenerateGuidedSearchSequenceArray(guideArray);
582
583  assert(array_n(hintDepthArray) == array_n(guideArray));
584
585  if (array_n(guideArray) == 0) hint = mdd_one(mddManager);
586
587  arrayForEachItem(mdd_t *, guideArray, hintnr, hint){
588
589    /* check the depth for which this hint is to be applied. */
590    hintDepth = array_fetch(int, hintDepthArray, hintnr);
591
592    if(hintnr == 0 && mdd_is_tautology(hint, 1) && array_n(guideArray) == 1){
593      assert(hintDepth == -1);
594    }  else {
595      assert(!incrementalFlag);
596      guidedSearchMode  = TRUE;
597      Fsm_InstantiateHint(fsm, hint, 1, 0, Ctlp_Underapprox_c,
598                          verbosityLevel > 1);
599      if (hintnr < (array_n(guideArray)-1))
600        fprintf(vis_stdout, "**GS info: Instantiating  hint number %d\n", hintnr+1);
601      else
602        fprintf(vis_stdout, "**GS info: Restoring original transition relation\n");
603
604      if (approxFlag == Fsm_Rch_Hd_c) {
605        /* clean up all the invalid state information */
606        if (hdInfo->interiorStates != NIL(mdd_t))
607          mdd_free(hdInfo->interiorStates);
608        hdInfo->interiorStates = NIL(mdd_t); /* for every new hint, this is invalid. */
609        if (hdInfo->interiorStateCandidate != NIL(mdd_t))
610          mdd_free(hdInfo->interiorStateCandidate);
611        hdInfo->interiorStateCandidate = NIL(mdd_t); /* for every new hint, this is invalid */
612        hdInfo->imageOfReachedComputed = FALSE; /* since it doesn't matter for every new hint */
613        if (hdInfo->deadEndResidue != NIL(mdd_t))
614          mdd_free(hdInfo->deadEndResidue);
615        hdInfo->deadEndResidue = NIL(mdd_t);
616      }
617      /* generate a frontier by doing a dead-end computation if the
618         frontier is empty. This is non-greedy for BFS and greedy for
619         HD. */
620      if (mdd_is_tautology(fromLowerBound, 0)) {
621        ComputeReachabilityParameters(mddManager, imageInfo, approxFlag,
622                                      &reachableStates, &fromUpperBound,
623                                      &fromLowerBound, &image, hdInfo,
624                                      initialStates,
625                                      mintermVarArray,
626                                      &depth, printStep,
627                                      shellFlag, onionRings,
628                                      verbosityLevel,
629                                      guidedSearchMode, hint, &hintDepth,
630                                      &notConverged);
631      }
632    }
633    /* initialize */
634    notConverged = FALSE;
635    if (!incrementalFlag)
636      Img_ImageInfoResetUseOptimizedRelationFlag(imageInfo);
637    /* Main loop of reachability computation. */
638    /* Iterate until fromLowerBound is empty or all states are reached. */
639    while (!mdd_is_tautology(fromLowerBound, 0)) {
640      if(depth > 0 && !incrementalFlag)
641        Img_ImageInfoSetUseOptimizedRelationFlag(imageInfo);
642      /* fromLowerBound is the "onion shell" of states just reached. */
643      if ((shellFlag && (approxFlag != Fsm_Rch_Hd_c) &&
644          (!firstTimeFlag ||
645           (Fsm_FsmReadReachabilityOnionRings(fsm) == NIL(array_t)))) ||
646          (shellFlag && (approxFlag == Fsm_Rch_Hd_c) &&
647          (Fsm_FsmReadReachabilityOnionRings(fsm) == NIL(array_t)) &&
648          firstTimeFlag)) {
649        array_insert_last(mdd_t*, onionRings, mdd_dup(fromLowerBound));
650      }
651
652      /* if it is the print step, print out the iteration and the */
653      if (printStep && ((depth % printStep) == 0)) {
654        int step;
655        /* for BFS, preserve earlier format of printing */
656        step = (shellFlag) ? array_n(onionRings) : Fsm_FsmGetReachableDepth(fsm)+depth;
657        PrintStatsPerIteration(approxFlag,
658                               nvars,
659                               step,
660                               hdInfo,
661                               mddManager,
662                               reachableStates,
663                               fromLowerBound,
664                               mintermVarArray);
665      }
666
667      /* Check if invariant contains the new states.  In case of HD
668       * computation, check the containment of the entire reached set.
669       */
670      if (invarStates != NIL(array_t)) {
671        mdd_t *temp;
672        temp = (approxFlag == Fsm_Rch_Hd_c) ? reachableStates : fromLowerBound;
673        if (!CheckStatesContainedInInvariant(temp, invarStates)) {
674          notConverged = TRUE;
675          invariantFailed = TRUE; /* flag used for early termination */
676          break;
677        }
678      }
679
680      if (mdd_is_tautology(reachableStates, 1)) {
681        break;
682      }
683
684      if ((depthValue && (depth == depthValue)) ||
685          /* limited depth hint is implemented this way */
686          (hintDepth == 0)) {
687        /* No more steps */
688        notConverged = TRUE;
689        break;
690      }
691
692      if (reorderFlag && !firstReorderFlag &&
693          (reachableStateSetSize >= reorderThreshold )){
694        firstReorderFlag = TRUE;
695        (void) fprintf(vis_stdout, "Dynamic variable ordering forced ");
696        (void) fprintf(vis_stdout, "with method sift\n");
697        Ntk_NetworkSetDynamicVarOrderingMethod(network,
698                                               BDD_REORDER_SIFT,
699                                               BDD_REORDER_VERBOSITY_DEFAULT);
700        bdd_reorder(Ntk_NetworkReadMddManager(network));
701        Ntk_NetworkSetDynamicVarOrderingMethod(network, currentMethod,
702                                               BDD_REORDER_VERBOSITY_DEFAULT);
703      }
704
705      firstTimeFlag = FALSE;
706      /* careSet for image computation is the set of all states not reached
707       * so far.
708       */
709      toCareSet = mdd_not(reachableStates);
710
711      /*
712       * Image of some set between lower and upper, where we care
713       * about the image only on unreached states.
714       */
715      if (incrementalFlag){
716        image = IncrementalImageCompute(network, fsm, mddManager,
717                                        fromLowerBound,
718                                        fromUpperBound, toCareSet,
719                                        arrayOfRoots, tableOfLeaves,
720                                        smoothVarArray, relationArray,
721                                        numLatch);
722      } else{
723        assert(!incrementalFlag);
724
725        if (approxFlag == Fsm_Rch_Hd_c) {
726          /* allow partial image computation */
727          Img_ImageAllowPartialImage(imageInfo, TRUE);
728        }
729
730        /* compute the image of this iteration */
731        image = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
732                                                      fromLowerBound,
733                                                      fromUpperBound,
734                                                      toCareSet);
735
736
737
738        /* record if partial image or not */
739        if (approxFlag == Fsm_Rch_Hd_c) {
740          /* Check if partial image computation, disallow partial image
741           * computation.
742           */
743          hdInfo->partialImage = Img_ImageWasPartial(imageInfo);
744          /* record this to prevent dead-end computation. */
745          hdInfo->imageOfReachedComputed = (!hdInfo->partialImage) &&
746            mdd_equal(reachableStates, fromLowerBound);
747          /* potential candidates for interior states (only if not a
748           * partial image)
749           */
750          if (!hdInfo->partialImage) hdInfo->interiorStateCandidate = mdd_dup(fromLowerBound);
751        }
752      }
753
754      /* free the used bdds */
755      mdd_free(toCareSet);
756
757      /* New lower bound is the states just reached. */
758      mdd_free(fromLowerBound);
759      fromLowerBound = mdd_and(image, reachableStates, 1, 0);
760      depth++;
761      hintDepth--;
762
763
764      if ((!incrementalFlag) && (approxFlag == Fsm_Rch_Hd_c)) {
765        FsmHdStatsComputeSizeAndMinterms(mddManager, image,
766                                         mintermVarArray, nvars,
767                                         Fsm_Hd_To, hdInfo->stats);
768      }
769
770      /* need image only if HD and not dead-end */
771      if (approxFlag != Fsm_Rch_Hd_c) {
772          mdd_free(image);
773          image = NULL;
774      } else {
775        if (hdInfo->imageOfReachedComputed ||   hdInfo->onlyPartialImage ||
776          (hdInfo->slowGrowth >= FSM_HD_NUM_SLOW_GROWTHS) ||
777          mdd_is_tautology(fromLowerBound, 0)) {
778          mdd_free(image);
779          image = NULL;
780        }
781      }
782
783      /* computes reachable states, fromlowerBound and fromupperbound
784       * for BFS.  For HD it computes the above as well as interior
785       * statess, dead-end residue, etc. All the other parameteres are
786       * updated. For guided search, this call does not perform a
787       * non-greedy dead-end computation, even if the frontier is 0. */
788       ComputeReachabilityParameters(mddManager, imageInfo, approxFlag,
789                                    &reachableStates,
790                                    &fromUpperBound,
791                                    &fromLowerBound,
792                                    &image,
793                                     hdInfo,
794                                    initialStates,
795                                    mintermVarArray,
796                                     &depth,  printStep,
797                                     shellFlag, onionRings,
798                                    verbosityLevel, FALSE, hint,
799                                    &hintDepth,
800                                    &notConverged);
801
802
803       if (mdd_is_tautology(fromLowerBound, 0) &&
804           (approxFlag == Fsm_Rch_Bfs_c) &&
805           (!guidedSearchMode) && (!depthValue))
806         depth--;
807
808    } /* end of main while loop (while frontier != 0) */
809
810    /* stop iterating over hint if invariants are violated or all
811       states are reachable or limited depth value has been
812       reached. */
813    if (invariantFailed) break;
814    if (mdd_is_tautology(reachableStates, 1)) {
815      break;
816    }
817    if (depthValue && (depth == depthValue)) {
818      /* No more steps */
819      break;
820    }
821
822  }/* for each hint */
823
824
825  if(!incrementalFlag &&
826     Img_ImageInfoObtainMethodType(imageInfo) == Img_Linear_c &&
827     Img_ImageInfoObtainOptimizeType(imageInfo) == Opt_NS &&
828     Img_IsTransitionRelationOptimized(imageInfo)) {
829    Img_ImageInfoResetUseOptimizedRelationFlag(imageInfo);
830    fprintf(vis_stdout, "%-20s%10g\n", "reachable states =",
831                 mdd_count_onset(mddManager, reachableStates,
832                                 fsm->fsmData.presentStateVars));
833    fromLowerBound = mdd_dup(reachableStates);
834    fromUpperBound = reachableStates;
835    while (1) {
836      toCareSet = mdd_dup(reachableStates);
837      image = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
838                                                  fromLowerBound,
839                                                  fromUpperBound,
840                                                  toCareSet);
841      newImage = bdd_or(image, initialStates, 1, 1);
842      bdd_free(image);
843      image = newImage;
844      if(mdd_equal(fromLowerBound, image)) {
845        mdd_free(toCareSet);
846        mdd_free(fromLowerBound);
847        mdd_free(reachableStates);
848        fromLowerBound = image;
849        reachableStates = mdd_dup(fromLowerBound);
850        fromUpperBound = reachableStates;
851        fprintf(vis_stdout, "%-20s%10g\n", "reachable states =",
852                 mdd_count_onset(mddManager, reachableStates,
853                                 fsm->fsmData.presentStateVars));
854        break;
855      }
856      mdd_free(toCareSet);
857      mdd_free(fromLowerBound);
858      mdd_free(reachableStates);
859      fromLowerBound = image;
860      reachableStates = mdd_dup(fromLowerBound);
861      fromUpperBound = reachableStates;
862
863      fprintf(vis_stdout, "%-20s%10g\n", "reachable states =",
864                 mdd_count_onset(mddManager, reachableStates,
865                                 fsm->fsmData.presentStateVars));
866    }
867  }
868
869
870  /* clean up for Guided search mainly, only if needed */
871  /* we rely on the fact that the variable hint is set to the last hint from
872   * the previous loop.
873   */
874  if (guidedSearchMode && !mdd_is_tautology(hint, 1))
875    Fsm_CleanUpHints(fsm, 1, 0, printStep);
876  array_free(hintDepthArray);
877
878  /* If (1) all states are reachable, or (2) not limited depth computation
879     and not a converge with a hint, or (3) limited depth and not
880     guided search mode and BFS and frontier = 0, or (4) in guided
881     search, if limited depth and frontier = 0 then one full dead-end
882     should have occured */
883  if(mdd_is_tautology(reachableStates, 1) ||
884     ((notConverged == FALSE) && mdd_is_tautology(hint, 1)) ||
885     (!guidedSearchMode && (notConverged == TRUE) &&
886      mdd_is_tautology(fromLowerBound, 0) && (approxFlag == Fsm_Rch_Bfs_c)) ||
887     (guidedSearchMode && hdInfo->deadEndWithOriginalTR &&
888      mdd_is_tautology(fromLowerBound, 0) && (approxFlag == Fsm_Rch_Bfs_c))) {
889
890    rchStatus = Fsm_Rch_Exact_c;
891    if (mdd_is_tautology(reachableStates, 1) &&
892        !mdd_is_tautology(fromLowerBound, 0) &&
893        printStep && ((depth % printStep) == 0) ) {
894      int step;
895      /* for BFS, preserve earlier format of printing */
896      step = (shellFlag) ?
897        array_n(onionRings) :
898        Fsm_FsmGetReachableDepth(fsm)+depth;
899      PrintStatsPerIteration(approxFlag, nvars, step, hdInfo,
900                             mddManager, reachableStates,
901                             fromLowerBound, mintermVarArray);
902    }
903  }
904
905  /* clean up the hints if allocated here */
906  if (guideArrayAllocated) mdd_array_free(guideArray);
907
908  if (hdInfo != NIL(FsmHdStruct_t)) {
909    FsmHdStructFree(hdInfo);
910  }
911
912  mdd_free(fromLowerBound);
913  mdd_free(initialStates);
914
915  /* Update FSM reahcability fields */
916
917  /* indicate whether the shells are consistent with the reachable states */
918  if (!shellFlag) {
919    /* if any states were added from a previous computation, shells
920       are not up-to-date */
921    if (Fsm_FsmReadCurrentReachableStates(fsm) != NIL(mdd_t)) {
922      if (!mdd_lequal(reachableStates, Fsm_FsmReadCurrentReachableStates(fsm), 1, 1)) {
923        FsmSetReachabilityOnionRingsUpToDateFlag(fsm, FALSE);
924      } /* otherwise the previous iteration was computed with onion
925      rings, in which case it is still up-to-date or the previous
926      iteration was computed without onion rings and it was set to not
927      up-to-date in the previous iteration */
928    } else {
929      assert(Fsm_FsmReadReachabilityOnionRings(fsm) == NIL(array_t));
930      /* not up-to-date because no onion rings */
931      FsmSetReachabilityOnionRingsUpToDateFlag(fsm, FALSE);
932    }
933
934  } else {
935    /* shells are up to date only if current set adds upto previously
936       computed states or more */
937    if (Fsm_FsmReadCurrentReachableStates(fsm)) {
938      if (!mdd_lequal(Fsm_FsmReadCurrentReachableStates(fsm),
939                    reachableStates, 1, 1)) {
940        FsmSetReachabilityOnionRingsUpToDateFlag(fsm, FALSE);
941      } else {
942        FsmSetReachabilityOnionRingsUpToDateFlag(fsm, TRUE);
943      }
944
945    } else FsmSetReachabilityOnionRingsUpToDateFlag(fsm, TRUE);
946
947    /* Onion rings are not BFS, i.e., HD or Guided search. */
948    if ((approxFlag == Fsm_Rch_Hd_c) ||
949        (Fsm_FsmReadReachabilityOnionRingsMode(fsm) == Fsm_Rch_Hd_c) ||
950        guidedSearchMode)
951      FsmSetReachabilityOnionRingsMode(fsm, Fsm_Rch_Hd_c);
952
953    if (array_n(onionRings) == 0) {
954      array_free(onionRings);
955      onionRings = NIL(array_t);
956    }
957    FsmSetReachabilityOnionRings(fsm, onionRings);
958  }
959
960  /* update fsm structure */
961  /* record depth of traversal, depth is consistent with reachable
962     states, hence may not be consistent with the onion rings */
963  /* replace reachable states if only more states have been computed now */
964  if (Fsm_FsmReadCurrentReachableStates(fsm) != NIL(mdd_t)) {
965    if (!mdd_lequal(reachableStates, Fsm_FsmReadCurrentReachableStates(fsm), 1, 1)) {
966      Fsm_FsmFreeReachableStates(fsm);
967      fsm->reachabilityInfo.reachableStates = mdd_dup(reachableStates);
968      if (!shellFlag) fsm->reachabilityInfo.depth = Fsm_FsmGetReachableDepth(fsm) + depth;
969      else if (Fsm_FsmReadReachabilityOnionRings(fsm))
970        fsm->reachabilityInfo.depth = array_n(Fsm_FsmReadReachabilityOnionRings(fsm));
971      /* set computation mode as HD if HD or Guided search, basically to indicate not BFS */
972      if ((approxFlag == Fsm_Rch_Hd_c) ||
973          (FsmReadReachabilityComputationMode(fsm)  == Fsm_Rch_Hd_c) ||
974          guidedSearchMode) {
975        FsmSetReachabilityComputationMode(fsm, Fsm_Rch_Hd_c);
976      }
977    }
978  } else {
979    fsm->reachabilityInfo.reachableStates = mdd_dup(reachableStates);
980    if (!shellFlag) fsm->reachabilityInfo.depth = depth;
981    else if (Fsm_FsmReadReachabilityOnionRings(fsm))
982      fsm->reachabilityInfo.depth = array_n(Fsm_FsmReadReachabilityOnionRings(fsm));
983    /* set computation mode as HD if HD or Guided search, basically to indicate not BFS */
984      if ((approxFlag == Fsm_Rch_Hd_c) || guidedSearchMode) {
985        FsmSetReachabilityComputationMode(fsm, Fsm_Rch_Hd_c);
986      } else {
987        FsmSetReachabilityComputationMode(fsm, Fsm_Rch_Bfs_c);
988      }
989
990  }
991  /* indicate whether reachability analysis is completed or not */
992  FsmSetReachabilityApproxComputationStatus(fsm, rchStatus);
993
994  if (incrementalFlag){
995    array_free(relationArray);
996    array_free(arrayOfRoots);
997    st_free_table(tableOfLeaves);
998    array_free(smoothVarArray);
999    /* Need to put in next state function data for the partition */
1000  }
1001
1002  return reachableStates;
1003} /* end of Fsm_FsmComputeReachableStates */
1004
1005
1006
1007/**Function********************************************************************
1008
1009  Synopsis [Existentially quantifies variables from an implicit product.]
1010
1011  Description [Existentially quantifies the smoothing variables from the
1012  product of the MDDs in mddArray, and returns the result. SmoothingVars is an
1013  array of MDD ids. For now, uses the simplistic approach of conjunction all
1014  the MDDs, and then quantifying the smoothing variables.]
1015
1016  SideEffects []
1017
1018******************************************************************************/
1019mdd_t *
1020Fsm_MddMultiwayAndSmooth(mdd_manager *mddManager, array_t *mddArray,
1021                         array_t *smoothingVars)
1022{
1023  int i;
1024  mdd_t *resultMdd;
1025  mdd_t *product = mdd_one(mddManager);
1026
1027  for (i = 0; i<array_n(mddArray); i++){
1028    mdd_t *mdd         = array_fetch(mdd_t*, mddArray, i);
1029    mdd_t *tempProduct = mdd_and(product, mdd, 1, 1);
1030    mdd_free(product);
1031    product = tempProduct;
1032  }
1033
1034  if (array_n(smoothingVars) == 0) {
1035    resultMdd = mdd_dup(product);
1036  }
1037  else{
1038    resultMdd =  mdd_smooth(mddManager, product, smoothingVars);
1039  }
1040
1041  mdd_free(product);
1042  return resultMdd;
1043}
1044
1045/**Function********************************************************************
1046
1047  Synopsis    [Prints the results of reachability analysis.]
1048
1049  Description    [Prints the results of reachability analysis.]
1050
1051  SideEffects []
1052
1053  SeeAlso     []
1054
1055******************************************************************************/
1056void
1057Fsm_FsmReachabilityPrintResults(
1058  Fsm_Fsm_t *fsm,
1059  long elapseTime,
1060  int approxFlag)
1061{
1062  mdd_manager   *mddManager = Fsm_FsmReadMddManager(fsm);
1063  mdd_t         *reachableStates = fsm->reachabilityInfo.reachableStates;
1064  array_t       *psVarsArray;
1065  int           nvars;
1066
1067  if (!reachableStates)
1068    return;
1069
1070  psVarsArray = Fsm_FsmReadPresentStateVars(fsm);
1071  /* compute number of present state variables */
1072  nvars = ComputeNumberOfBinaryStateVariables(mddManager, psVarsArray);
1073
1074  (void) fprintf(vis_stdout,"********************************\n");
1075  (void) fprintf(vis_stdout,"Reachability analysis results:\n");
1076  if ((FsmReadReachabilityComputationMode(fsm) == Fsm_Rch_Bfs_c) &&
1077      (Fsm_FsmReadReachableStates(fsm) != NIL(mdd_t))) {
1078    (void) fprintf(vis_stdout, "%-20s%10d\n", "FSM depth =",
1079                   fsm->reachabilityInfo.depth);
1080  } else {
1081    (void) fprintf(vis_stdout, "%-20s%10d\n", "computation depth =",
1082                   fsm->reachabilityInfo.depth);
1083  }
1084  if (nvars <= 1023) {
1085    (void) fprintf(vis_stdout, "%-20s%10g\n", "reachable states =",
1086                   mdd_count_onset(mddManager, reachableStates,
1087                                   fsm->fsmData.presentStateVars));
1088  } else {
1089    /*
1090    (void) fprintf(vis_stdout, "%-20s", "reachable states = ");
1091    bdd_print_apa_minterm(vis_stdout, reachableStates, nvars, (long)6);
1092    */
1093    EpDouble    epd;
1094    char        strValue[20];
1095
1096    mdd_epd_count_onset(mddManager, reachableStates,
1097                        fsm->fsmData.presentStateVars, &epd);
1098    EpdGetString(&epd, strValue);
1099    (void) fprintf(vis_stdout, "%-20s%10s\n", "reachable states =", strValue);
1100  }
1101  (void) fprintf(vis_stdout, "%-20s%10d\n", "BDD size =",
1102                 mdd_size(reachableStates));
1103  (void) fprintf(vis_stdout, "%-20s%10g\n", "analysis time =",
1104                 (double)elapseTime/1000.0);
1105  if (Fsm_FsmReadReachableStates(fsm) != NIL(mdd_t)) {
1106    (void) fprintf(vis_stdout, "%-20s%10s\n", "reachability analysis = ", "complete");
1107  } else {
1108    (void) fprintf(vis_stdout, "%-20s%10s\n", "reachability analysis = ", "incomplete");
1109  }
1110}
1111
1112
1113/*---------------------------------------------------------------------------*/
1114/* Definition of static functions                                          */
1115/*---------------------------------------------------------------------------*/
1116
1117/**Function********************************************************************
1118
1119  Synopsis    [Checks the validity of image]
1120
1121  Description [In a properly formed image, there should not be any
1122  domain or quantify variables in its support. This function checks
1123  for that fact.]
1124
1125  SideEffects []
1126
1127******************************************************************************/
1128static int
1129CheckImageValidity(mdd_manager *mddManager, mdd_t *image, array_t
1130                   *domainVarMddIdArray, array_t *quantifyVarMddIdArray)
1131{
1132  int i;
1133  array_t *imageSupportArray = mdd_get_support(mddManager, image);
1134  st_table *imageSupportTable = st_init_table(st_numcmp, st_numhash);
1135  for (i=0; i<array_n(imageSupportArray); i++){
1136    int mddId = array_fetch(int, imageSupportArray, i);
1137    (void) st_insert(imageSupportTable, (char *) (long) mddId, NIL(char));
1138  }
1139  for (i=0; i<array_n(domainVarMddIdArray); i++){
1140    int domainVarId;
1141    domainVarId = array_fetch(int, domainVarMddIdArray, i);
1142    assert(st_is_member(imageSupportTable, (char *)(long)domainVarId) == 0);
1143  }
1144  for (i=0; i<array_n(quantifyVarMddIdArray); i++){
1145    int quantifyVarId;
1146    quantifyVarId = array_fetch(int, quantifyVarMddIdArray, i);
1147    assert(st_is_member(imageSupportTable, (char *)(long)quantifyVarId) == 0);
1148  }
1149  st_free_table(imageSupportTable);
1150  array_free(imageSupportArray);
1151  return 1;
1152}
1153
1154/**Function********************************************************************
1155
1156  Synopsis    [Counts the number of Bdd variables for the given Mdd id array].
1157
1158  Description [Counts the number of Bdd variables for the given Mdd id array]
1159
1160
1161  SideEffects []
1162
1163******************************************************************************/
1164/*static*/ int
1165ComputeNumberOfBinaryStateVariables(mdd_manager *mddManager,
1166                               array_t *mddIdArray)
1167{
1168  int mddId, i;
1169  mvar_type mddVar;
1170  int numEncodingBits, count = 0;
1171  array_t *mvar_list = mdd_ret_mvar_list(mddManager);
1172
1173  arrayForEachItem(int, mddIdArray, i, mddId) {
1174    mddVar = array_fetch(mvar_type, mvar_list, mddId);
1175    numEncodingBits = mddVar.encode_length;
1176    count += numEncodingBits;
1177  }
1178  return count;
1179} /* end of ComputeNumberOfBinaryStateVariables */
1180
1181
1182/**Function********************************************************************
1183
1184  Synopsis    [Add states.]
1185
1186  Description [Add States.]
1187
1188  SideEffects [ Free the original parts]
1189
1190******************************************************************************/
1191static mdd_t *
1192AddStates(mdd_t *a, mdd_t *b, int freeA, int freeB)
1193{
1194  mdd_t *result;
1195  if ((a != NULL) && (b != NULL)) {
1196    result = mdd_or(a, b, 1, 1);
1197  } else if ((a == NULL) && (b == NULL)) {
1198    result = a;
1199  } else if (a == NULL) {
1200    result = mdd_dup(b);
1201  } else {
1202    result =  mdd_dup(a);
1203  }
1204  if ((freeA == FSM_MDD_FREE) && (a != NULL)) mdd_free(a);
1205  if ((freeB == FSM_MDD_FREE) && (b != NULL)) mdd_free(b);
1206  return result;
1207} /* end of AddStates */
1208
1209
1210/**Function********************************************************************
1211
1212  Synopsis    [Simulates randomly specified number of states.]
1213
1214  Description [Simulates randomly specified number of states.]
1215
1216  SideEffects []
1217
1218******************************************************************************/
1219static void
1220RandomSimulation(int simNVec,
1221                 Fsm_Fsm_t *fsm,
1222                 Fsm_RchType_t approxFlag,
1223                 mdd_t *initialStates,
1224                 mdd_t **reachableStates,
1225                 mdd_t **fromLowerBound,
1226                 FsmHdStruct_t *hdInfo)
1227{
1228  Ntk_Network_t   *network = fsm->network;
1229
1230  /* Compute specified number of simulated states. */
1231  *reachableStates = Sim_RandomSimulate(network, simNVec, 0);
1232  *reachableStates = AddStates(*reachableStates, initialStates, FSM_MDD_FREE, FSM_MDD_DONT_FREE);
1233  *fromLowerBound = mdd_dup(*reachableStates);
1234
1235  if (approxFlag == Fsm_Rch_Hd_c) {
1236    if (mdd_size(*fromLowerBound) >
1237        Fsm_FsmHdOptionReadFrontierApproxThreshold(hdInfo->options)) {
1238      /* Reset frontier if too large. */
1239      mdd_free(*fromLowerBound);
1240      *fromLowerBound = bdd_between(initialStates, *reachableStates);
1241      if (!mdd_equal(*fromLowerBound, *reachableStates)) {
1242        hdInfo->firstSubset = FALSE;
1243        hdInfo->deadEndResidue = mdd_and(*reachableStates,
1244                                         *fromLowerBound, 1, 0);
1245      }
1246    }
1247  }
1248  return;
1249} /* end of RandomSimulation */
1250
1251
1252/**Function********************************************************************
1253
1254  Synopsis    [Prints stats per iteration]
1255
1256  Description [Prints stats per iteration]
1257
1258  SideEffects []
1259
1260******************************************************************************/
1261static void
1262PrintStatsPerIteration(Fsm_RchType_t approxFlag,
1263                       int nvars,
1264                       int depth,
1265                       FsmHdStruct_t *hdInfo,
1266                       mdd_manager *mddManager,
1267                       mdd_t *reachableStates,
1268                       mdd_t *fromLowerBound,
1269                       array_t *mintermVarArray)
1270{
1271  if (approxFlag != Fsm_Rch_Hd_c) {
1272    int reachableStateSetSize = mdd_size(reachableStates);
1273    if (nvars <= 1023) {
1274      (void)fprintf(vis_stdout, "BFS step = %d\t|states| = %8g\tBdd size = %8ld\n",
1275                    depth, mdd_count_onset(mddManager, reachableStates,
1276                                           mintermVarArray),
1277                    (long)reachableStateSetSize);
1278      /*                            bdd_print_minterm(reachableStates); */
1279    } else {
1280      (void)fprintf(vis_stdout, "BFS step = %d\tBdd size = %8d\t|states| = ",
1281                    depth, reachableStateSetSize);
1282      (void) bdd_print_apa_minterm(vis_stdout, reachableStates, nvars, (long)6);
1283    }
1284
1285  } else { /* HD */
1286
1287    if (nvars <= 1023) {
1288      (void)fprintf(vis_stdout, "Step = %d, R = %8g, |R| = %8d,  I = %8g,  |I| = %8d\n",
1289                    depth,  FsmHdStatsReadMintermReached(hdInfo->stats),
1290                    FsmHdStatsReadSizeReached(hdInfo->stats), FsmHdStatsReadMintermTo(hdInfo->stats) ,
1291                    FsmHdStatsReadSizeTo(hdInfo->stats));
1292      (void)fprintf(vis_stdout, "Completed iteration %d at %g seconds\n",
1293                    depth, (util_cpu_time()/1000.0));
1294
1295      (void)fprintf(vis_stdout, "Step = %d, F = %8g, |F| = %8d, FA = %8g, |FA| = %8d\n",
1296                    depth+1, FsmHdStatsReadMintermFrom(hdInfo->stats),
1297                    FsmHdStatsReadSizeFrom(hdInfo->stats),
1298                    FsmHdStatsReadMintermFromSubset(hdInfo->stats),
1299                    FsmHdStatsReadSizeFromSubset(hdInfo->stats));
1300    } else {
1301      int status;
1302      (void)fprintf(vis_stdout, "Step = %d, |R| = %8d, R = ",
1303                    depth, FsmHdStatsReadSizeReached(hdInfo->stats));
1304      status = bdd_print_apa_minterm(vis_stdout, reachableStates, nvars, (long)6);
1305      if (!status) {
1306        error_append("** rch error: Error in printing arbitrary precision minterm count of Reached");
1307      }
1308
1309      (void)fprintf(vis_stdout, "Completed iteration %d at %g seconds\n",
1310                    depth, (util_cpu_time()/1000.0));
1311      (void)fprintf(vis_stdout, "Step = %d, |F| = %8d, F = %8g, |FA| = %8d, FA = ",
1312                    depth, FsmHdStatsReadSizeFrom(hdInfo->stats), 0.0,
1313                    FsmHdStatsReadSizeFromSubset(hdInfo->stats) );
1314      status = bdd_print_apa_minterm(vis_stdout, fromLowerBound, nvars, 6);
1315      if (!status) {
1316        error_append("** rch error: Error in printing arbitrary precision minterm count of From");
1317      }
1318    }
1319  }
1320  return;
1321} /* end of PrintStatsPerIteration */
1322
1323/**Function********************************************************************
1324
1325  Synopsis [Induce full dead-end if there is a big jump in Reached
1326  size]
1327
1328  Description [Induce full dead-end if there is a big jump in Reached
1329  size and not enough increase in minterms of Reached. So throw away
1330  the new large-sized Reached and compute its entire image. Use the
1331  dead-end computation for this and use the non-greedy flag. This is a
1332  recovery mechanism to combat fragmentation of the state space.]
1333
1334  SideEffects [Other quantities are adjusted accordingly. Now the Reached
1335  set before the dead-end computation will be added to the interior states.]
1336
1337******************************************************************************/
1338static void
1339HdInduceFullDeadEndIfNecessary(mdd_manager *mddManager,
1340                               Img_ImageInfo_t *imageInfo,
1341                               mdd_t **fromLowerBound,
1342                               mdd_t **fromUpperBound,
1343                               mdd_t **reachableStates,
1344                               mdd_t **image,
1345                               FsmHdStruct_t *hdInfo,
1346                               int *depth,
1347                               int shellFlag,
1348                               array_t *onionRings,
1349                               array_t *mintermVarArray,
1350                               int oldSize,
1351                               double oldMint,
1352                               int verbosityLevel)
1353{
1354  int nvars =  Fsm_FsmHdOptionReadNumVars(hdInfo->options);
1355  /*
1356   * Compute a full (non-greedy) dead-end when a dead-end computation
1357   * hasn't occurred, and the jump in minterms is lower than MINT_GROWTH and
1358   * either the old reached size is between MID_SIZE and LARGE_SIZE and the
1359   * jump is MID_SIZE or the new size is larger than LARGE_SIZE and the jump
1360   * is LARGE_SIZE.
1361   */
1362  if ((hdInfo->deadEndComputation == FALSE) &&
1363      ((FsmHdStatsReadMintermReached(hdInfo->stats) - oldMint)/oldMint < FSM_HD_MINT_GROWTH) &&
1364      (((FsmHdStatsReadSizeReached(hdInfo->stats)  > FSM_HD_MID_SIZE) &&
1365        (FsmHdStatsReadSizeReached(hdInfo->stats) - oldSize > FSM_HD_MID_SIZE) &&
1366        (oldSize > FSM_HD_MID_SIZE) && (oldSize < FSM_HD_LARGE_SIZE)) ||
1367       ((FsmHdStatsReadSizeReached(hdInfo->stats) > FSM_HD_LARGE_SIZE) &&
1368        (FsmHdStatsReadSizeReached(hdInfo->stats) - oldSize > FSM_HD_LARGE_SIZE)))) {
1369    if (verbosityLevel >= 2) {
1370      fprintf(vis_stdout, "Full Dead End: New Reached = %d, Minterms = %g\n",
1371              FsmHdStatsReadSizeReached(hdInfo->stats), FsmHdStatsReadMintermReached(hdInfo->stats));
1372    }
1373
1374    if (*image != NULL) {
1375      mdd_free(*image);
1376      *image = NULL;
1377    }
1378    /* throw away the reached with the jump in size */
1379    mdd_free(*reachableStates);
1380    if (shellFlag && onionRings) {
1381      mdd_free(array_fetch(mdd_t *, onionRings, array_n(onionRings)-1));
1382      array_insert(mdd_t *, onionRings, array_n(onionRings)-1, NIL(mdd_t));
1383    }
1384
1385    *reachableStates = *fromUpperBound;
1386    /* throw away interior state candidates since we just threw away
1387     * the new states
1388     */
1389    if (hdInfo->interiorStateCandidate != NIL(mdd_t)) {
1390      mdd_free(hdInfo->interiorStateCandidate);
1391      hdInfo->interiorStateCandidate = NIL(mdd_t);
1392    }
1393
1394    if (verbosityLevel >= 2) {
1395      /* record number of dead ends */
1396      (hdInfo->numDeadEnds)++;
1397      fprintf(vis_stdout, "Dead-End %d at %g seconds - FULL\n",
1398              hdInfo->numDeadEnds, (util_cpu_time()/1000.0));
1399    }
1400
1401    /* perform a full non-greedy dead-end computation */
1402    *fromLowerBound = FsmHdDeadEnd(mddManager, imageInfo, *reachableStates,
1403                                  hdInfo,
1404                                  mintermVarArray,
1405                                  FSM_HD_NONGREEDY, verbosityLevel);
1406    (*depth)++;
1407    /* update reached since a new set of seeds have been found */
1408    assert (!mdd_is_tautology(*fromLowerBound, 0));
1409    if (shellFlag && onionRings) {
1410      mdd_t *temp = mdd_and(*fromLowerBound, *reachableStates, 1, 0);
1411      if (!mdd_is_tautology(temp, 0))
1412        array_insert(mdd_t *, onionRings, array_n(onionRings)-1, temp);
1413      else
1414        mdd_free(temp);
1415    }
1416    *fromUpperBound = *reachableStates;
1417    *reachableStates = mdd_or(*fromLowerBound, *fromUpperBound, 1, 1);
1418    FsmHdStatsComputeSizeAndMinterms(mddManager, *reachableStates,
1419                                     mintermVarArray,  nvars,
1420                                     Fsm_Hd_Reached, hdInfo->stats);
1421  } /* end of if jump in Reached */
1422} /* end of  HdInduceFullDeadEndIfNecessary */
1423
1424
1425/**Function********************************************************************
1426
1427  Synopsis [Compute initial states.]
1428
1429  Description [Compute initial states. Return fsm initial states if no
1430  previously computed states are found. If shell flag, compute union
1431  of rings. If not shell flag, return previously computed states.]
1432
1433  SideEffects []
1434
1435******************************************************************************/
1436static mdd_t *
1437ComputeInitialStates(Fsm_Fsm_t *fsm, int shellFlag, boolean printWarning)
1438{
1439  mdd_t *initialStates = NIL(mdd_t);
1440  boolean rings = FALSE;
1441  array_t *mintermVarArray = Fsm_FsmReadPresentStateVars(fsm);
1442
1443  if (Fsm_FsmReadCurrentReachableStates(fsm) == NIL(mdd_t)) {
1444    initialStates = Fsm_FsmComputeInitialStates(fsm);
1445    return (initialStates);
1446  } else if (shellFlag) {
1447    (void) Fsm_FsmReachabilityOnionRingsStates(fsm, &initialStates);
1448    if (initialStates == NIL(mdd_t)) {
1449      initialStates = Fsm_FsmComputeInitialStates(fsm);
1450      return (initialStates);
1451    } else if (mdd_is_tautology(initialStates, 0)) {
1452      initialStates = Fsm_FsmComputeInitialStates(fsm);
1453      return (initialStates);
1454    }
1455    /* some states are found in the onion rings */
1456    rings = TRUE;
1457  } else {
1458    /* use previously computed states */
1459    initialStates = mdd_dup(Fsm_FsmReadCurrentReachableStates(fsm));
1460  }
1461  if (printWarning) {
1462    fprintf(vis_stdout, "** rch warning: Starting reachability analysis from previously computed states.\n");
1463    fprintf(vis_stdout, "** rch warning: Use compute_reach -F to recompute if necessary.\n");
1464    fprintf(vis_stdout, "** rch warning: Previously computed states = %g, Size = %d, computation depth = 0-%d\n", mdd_count_onset(Fsm_FsmReadMddManager(fsm), initialStates, mintermVarArray), mdd_size(initialStates), fsm->reachabilityInfo.depth);
1465    if (!rings) {
1466      if (FsmReadReachabilityComputationMode(fsm) == Fsm_Rch_Bfs_c) {
1467        fprintf(vis_stdout, "** rch warning: Previous computation done with BFS (-A 0 option)\n");
1468      } else if (FsmReadReachabilityComputationMode(fsm) == Fsm_Rch_Hd_c) {
1469        fprintf(vis_stdout, "** rch warning: Some previous computations done using BFS/DFS mode (-A 1 or -g option)\n");
1470      }
1471    } else {
1472      if (Fsm_FsmReadReachabilityOnionRingsMode(fsm) == Fsm_Rch_Bfs_c) {
1473        fprintf(vis_stdout, "** rch warning: Previous onion rings computed with BFS (-A 0 option)\n");
1474      } else if (Fsm_FsmReadReachabilityOnionRingsMode(fsm) == Fsm_Rch_Hd_c) {
1475        fprintf(vis_stdout, "** rch warning: Some set of onion rings have been computed using BFS/DFS (-A 1 or -g option)\n");
1476      }
1477    }
1478  }
1479  return (initialStates);
1480} /* end of ComputeInitialStates */
1481
1482
1483/**Function********************************************************************
1484
1485  Synopsis [Checks if the reachable states are contained in each
1486  element of an array of invariants.]
1487
1488  Description [Checks if the reachable states are contained in each
1489  element of an array of invariants. Returns 0 as soon as a violation
1490  is found.]
1491
1492  SideEffects []
1493
1494******************************************************************************/
1495static int
1496CheckStatesContainedInInvariant(mdd_t *reachableStates,
1497                                array_t *invarStates)
1498{
1499  int i;
1500  mdd_t *invariant;
1501
1502  arrayForEachItem(mdd_t *, invarStates, i, invariant) {
1503    if (invariant == NIL(mdd_t)) continue;
1504    if (!mdd_lequal(reachableStates, invariant, 1, 1)) {
1505      return 0;
1506    }
1507  }
1508  return 1;
1509}
1510
1511/**Function********************************************************************
1512
1513  Synopsis [Computes the reachable states, fromLowerBound and
1514  fromUpperBound for HD Traversal.]
1515
1516  Description [Computes the reachable states, fromLowerBound and
1517  fromUpperBound for HD Traversal. Updates all other arguments such as
1518  interiorStates, deadEndResidue . There are 3 major operations in
1519  this procedure. 1. Induce (if slow growth in reached) and compute a
1520  dead-end if necessary. 2. Compute the image of Reached if there is a
1521  big jump in its size. 3. Compute a dense subset of states to be used
1522  as a frontier in the next iteration.
1523
1524  1. A dead-end is the situation where no new states have been
1525  produced (fromLowerBound = 0), It is induced if the rate of growth
1526  of Reached is slow. If the image of the Entire Reached set has been
1527  computed in the previous iteration, then pretend this is a dead-end.
1528
1529  2. If the jump in Reached is large, compute its entire image to
1530  recover from fragmentation.
1531
1532  3. A dense subset of the frontier set is computed to be used as the
1533  frontier set in the next iteration. The update of reached is
1534  performed in this step (may not add scrap states if
1535  specified.). If a dead-end has just been performed, the new states
1536  are always added to Reached. Growth rate monitors are also
1537  updated. ]
1538
1539  SideEffects []
1540
1541******************************************************************************/
1542static void
1543HdComputeReachabilityParameters(mdd_manager *mddManager,
1544                                Img_ImageInfo_t *imageInfo,
1545                                mdd_t **reachableStates,
1546                                mdd_t **fromUpperBound,
1547                                mdd_t **fromLowerBound,
1548                                mdd_t **image,
1549                                FsmHdStruct_t *hdInfo,
1550                                mdd_t *initialStates,
1551                                array_t *mintermVarArray,
1552                                int *depth,
1553                                int printStep,
1554                                int shellFlag,
1555                                array_t *onionRings,
1556                                int verbosityLevel)
1557{
1558  float growth;
1559  boolean scrapStates;
1560  int nvars = Fsm_FsmHdOptionReadNumVars(hdInfo->options);
1561  int oldSize;
1562  double oldMint;
1563  int sizeOfOnionRings = 0;
1564  if (shellFlag && onionRings) {
1565    sizeOfOnionRings = array_n(onionRings);
1566  }
1567
1568  verbosityLevel = (printStep && (((*depth) % printStep) == 0)) ? verbosityLevel : 0;
1569
1570  /* keep image if small, record size of the image */
1571  oldSize = FsmHdStatsReadSizeReached(hdInfo->stats);
1572  oldMint = FsmHdStatsReadMintermReached(hdInfo->stats);
1573  FsmHdStatsReset(hdInfo->stats, Fsm_Hd_Reached);
1574  FsmHdStatsReset(hdInfo->stats, Fsm_Hd_FromSubset);
1575  FsmHdStatsReset(hdInfo->stats, Fsm_Hd_From);
1576
1577  scrapStates =  Fsm_FsmHdOptionReadScrapStates(hdInfo->options);
1578  hdInfo->onlyPartialImage =  Fsm_FsmHdOptionReadOnlyPartialImage(hdInfo->options);
1579
1580  /* Step 1: Check comments at the top of this function */
1581  /* Check if this is a dead end */
1582  /* if growth rate of reached is really small, induce a dead-end */
1583  hdInfo->deadEndComputation = FALSE;
1584  if ((hdInfo->imageOfReachedComputed) ||
1585      (mdd_is_tautology(*fromLowerBound, 0)) ||
1586      (hdInfo->slowGrowth >= 5)) {
1587    /*
1588     * if image of reached is computed, add to the dead states.
1589     * Set dead-end computation flag and add all new states to Reached.
1590     */
1591
1592    /* add to interior states */
1593    hdInfo->interiorStates = AddStates(hdInfo->interiorStates,
1594                                       hdInfo->interiorStateCandidate,
1595                                       FSM_MDD_FREE, FSM_MDD_FREE);
1596    hdInfo->interiorStateCandidate = NIL(mdd_t);
1597    if ((verbosityLevel >= 2) && (hdInfo->interiorStates != NIL(mdd_t))) {
1598      fprintf(vis_stdout, "Interior states added, Size = %d, Minterms = %g\n",
1599              mdd_size(hdInfo->interiorStates), mdd_count_onset(mddManager,
1600                                        hdInfo->interiorStates, mintermVarArray));
1601    }
1602
1603    hdInfo->deadEndComputation = TRUE;
1604    hdInfo->firstSubset = FALSE;
1605    hdInfo->slowGrowth = 0;
1606    hdInfo->lastIter = *depth;
1607
1608    if (!hdInfo->imageOfReachedComputed) {
1609      /* Either slow growth or real dead-end */
1610      if (verbosityLevel >= 2) {
1611        if (!mdd_is_tautology(*fromLowerBound, 0))
1612          fprintf(vis_stdout, "Dead-End triggered by slow growth\n");
1613        /* record number of dead ends */
1614        (hdInfo->numDeadEnds)++;
1615        fprintf(vis_stdout, "Dead-End %d at %g seconds\n", hdInfo->numDeadEnds,
1616                (util_cpu_time()/1000.0));
1617      }
1618
1619      /* add another onion ring. */
1620      if (shellFlag && onionRings && !mdd_is_tautology(*fromLowerBound, 0)) {
1621        mdd_t *temp = mdd_and(*fromLowerBound, *reachableStates, 1, 0);
1622        if (!mdd_is_tautology(temp, 0))
1623          array_insert_last(mdd_t *, onionRings, temp);
1624        else
1625          mdd_free(temp);
1626      }
1627      *reachableStates = AddStates(*fromLowerBound, *reachableStates,
1628                                  FSM_MDD_FREE, FSM_MDD_FREE);
1629      *fromUpperBound = *reachableStates;
1630
1631          /* perform a dead-end computation */
1632      *fromLowerBound = FsmHdDeadEnd(mddManager, imageInfo, *reachableStates,
1633                                    hdInfo,
1634                                    mintermVarArray,
1635                                    FSM_HD_GREEDY, verbosityLevel);
1636
1637      (*depth)++;
1638    }
1639  } /* end of if dead-end computation */
1640
1641  /* Step 2: Check comments at the top of this function */
1642  if (!mdd_is_tautology(*fromLowerBound, 0)) {
1643    /* add another onion ring. */
1644    if (shellFlag && onionRings) {
1645      mdd_t *temp = mdd_and(*fromLowerBound, *reachableStates, 1, 0);
1646      if (!mdd_is_tautology(temp, 0))
1647        array_insert_last(mdd_t *, onionRings, temp);
1648      else
1649        mdd_free(temp);
1650    }
1651    /* compute reachable states with new states */
1652    *fromUpperBound = *reachableStates;
1653    *reachableStates = mdd_or(*fromLowerBound, *fromUpperBound, 1, 1);
1654    FsmHdStatsComputeSizeAndMinterms(mddManager, *reachableStates,
1655                                     mintermVarArray, nvars,
1656                                     Fsm_Hd_Reached, hdInfo->stats);
1657
1658
1659    /*
1660         * induce a full dead-end computation if jump in size of Reached is
1661         * large. But when the image of Reached has been computed or a dead-end
1662         * computation was just done, this is not done because deadEndComputation
1663         * has been set to 1.
1664         */
1665    HdInduceFullDeadEndIfNecessary(mddManager, imageInfo, fromLowerBound,
1666                                   fromUpperBound, reachableStates, image,
1667                                   hdInfo, depth, shellFlag, onionRings,
1668                                   mintermVarArray, oldSize,
1669                                   oldMint, verbosityLevel);
1670  } /* end of  if (!mdd_is_tautology(fromLowerBound, 0)) */
1671
1672  /* Step 3: Check comments at the top of this function */
1673  /* Create subset if necessary */
1674  if (!mdd_is_tautology(*fromLowerBound, 0)) {
1675    if (!hdInfo->onlyPartialImage) {
1676      mdd_t *newStates;
1677      /*
1678       * Now fromUpperBound has the old reached states, reachableStates
1679       * has the new set of states.
1680       */
1681      newStates = mdd_dup(*fromLowerBound);
1682      FsmHdFromComputeDenseSubset(mddManager, fromLowerBound,
1683                                  fromUpperBound, reachableStates,
1684                                  image, initialStates, hdInfo,
1685                                  shellFlag, onionRings, sizeOfOnionRings,
1686                                  mintermVarArray);
1687
1688      /* if all new states are chosen from the previous iteration and
1689       * all these states have been added then add to interior states.
1690       * All new states are sometimes not added when
1691       * hdInfo->options->scrapStates is 0. Dead-end computations need not be
1692       * considered here since the interior states were already added then.
1693       */
1694      if ((hdInfo->interiorStateCandidate != NIL(mdd_t)) &&
1695          ((mdd_lequal(newStates, *fromLowerBound, 1, 1)) ||
1696           (scrapStates == TRUE))) {
1697        hdInfo->interiorStates = AddStates(hdInfo->interiorStates, hdInfo->interiorStateCandidate,
1698                                   FSM_MDD_FREE, FSM_MDD_FREE);
1699        hdInfo->interiorStateCandidate = NIL(mdd_t);
1700        if (verbosityLevel >= 2) {
1701          fprintf(vis_stdout,
1702                  "Interior states added, Size = %d, Minterms = %g\n",
1703                  mdd_size(hdInfo->interiorStates),
1704                  mdd_count_onset(mddManager, hdInfo->interiorStates,
1705                                  mintermVarArray));
1706        }
1707      }
1708      mdd_free(newStates);
1709
1710      /* end of if fromLowerbound == 0 && subset Flag*/
1711    } else  {
1712      mdd_free(*fromUpperBound);
1713      if (printStep && ((*depth) % printStep == 0)) {
1714        FsmHdStatsComputeSizeAndMinterms(mddManager, *fromLowerBound,
1715                                         mintermVarArray, nvars, Fsm_Hd_From, hdInfo->stats);
1716        FsmHdStatsSetMintermFromSubset(hdInfo->stats, 0.0);
1717        FsmHdStatsSetSizeFromSubset(hdInfo->stats, 0);
1718      }
1719      *fromUpperBound = *reachableStates;
1720    }
1721  } /* end of if fromLowerBound == 0 */
1722  if (hdInfo->interiorStateCandidate != NIL(mdd_t)) {
1723    mdd_free(hdInfo->interiorStateCandidate);
1724    hdInfo->interiorStateCandidate = NIL(mdd_t);
1725  }
1726
1727  /* monitor growth rate of reached, record if slow growth in consecutive
1728   * iterations
1729   */
1730  if (!mdd_is_tautology(*fromLowerBound, 0)) {
1731    FsmHdStatsComputeSizeAndMinterms(mddManager, *reachableStates,
1732                                     mintermVarArray, nvars, Fsm_Hd_Reached, hdInfo->stats);
1733    growth = (float)(FsmHdStatsReadMintermReached(hdInfo->stats) - oldMint)/
1734      (float)oldMint;
1735    if ((growth < FSM_HD_GROWTH_RATE) &&
1736        (((hdInfo->slowGrowth) && ((*depth) == (hdInfo->lastIter) + 1)) || (!(hdInfo->slowGrowth)))) {
1737      if (verbosityLevel >= 2) {
1738        fprintf(vis_stdout, "Growth rate = %f\n", growth);
1739      }
1740      (hdInfo->slowGrowth)++;
1741      hdInfo->lastIter = *depth;
1742    } else {
1743      /* reset value */
1744      hdInfo->slowGrowth = 0;
1745    }
1746  }
1747  return;
1748} /* end of HdComputeReachabilityParameters */
1749
1750/**Function********************************************************************
1751
1752  Synopsis [Initializes parameters for incremental computation.]
1753
1754  Description [Initializes parameters for incremental computation.
1755  Instantiates arrayOfRoots and tableOfLeafs, and returns the number of latches
1756  in the sytstem.  Upon return, arrayOfRoots is an array of Ntk_Node_t *, and
1757  tableOfLeaves is an st_table of Ntk_Node_t *.]
1758
1759  SideEffects []
1760
1761******************************************************************************/
1762static int
1763InitializeIncrementalParameters(
1764  Fsm_Fsm_t *fsm,
1765  Ntk_Network_t *network,
1766  array_t **arrayOfRoots,
1767  st_table **tableOfLeaves)
1768{
1769  int numLatch;
1770  Ntk_Node_t *node;
1771  lsGen gen;
1772  int i, mddId;  /* iterate over the nextStateVars of the fsm */
1773
1774  numLatch = Ntk_NetworkReadNumLatches(network);
1775
1776  /* This changed to fix a bug.  Instead of reading the roots using
1777     Ntk_NetworkForEachCombOutput, we now get them from
1778     fsm->fsdData.nextStateVars, which means that the order is consistent with
1779     the latter field, as required later on in the incremental reachability
1780     code
1781
1782     old code:
1783     *arrayOfRoots = array_alloc(Ntk_Node_t *, numLatch);
1784     Ntk_NetworkForEachCombOutput(network, gen, node) {
1785     if(Ntk_NodeTestIsLatchDataInput(node)){
1786     array_insert_last(Ntk_Node_t *, *arrayOfRoots, node);
1787    }
1788  }
1789  */
1790
1791  assert(numLatch == array_n(fsm->fsmData.nextStateVars));
1792  *arrayOfRoots = array_alloc(Ntk_Node_t *, numLatch);
1793
1794  arrayForEachItem(int, fsm->fsmData.nextStateVars, i, mddId){
1795    Ntk_Node_t *shadow;
1796    Ntk_Node_t *latch;
1797    Ntk_Node_t *dataInput;
1798
1799    shadow = Ntk_NetworkFindNodeByMddId(network, mddId);
1800    assert(Ntk_NodeTestIsShadow(shadow));
1801    latch = Ntk_ShadowReadOrigin(shadow);
1802    assert(Ntk_NodeTestIsLatch(latch));
1803    dataInput = Ntk_LatchReadDataInput(latch);
1804    assert(dataInput != NIL(Ntk_Node_t));
1805
1806    array_insert(Ntk_Node_t *, *arrayOfRoots, i, dataInput);
1807  }
1808
1809  *tableOfLeaves = st_init_table(st_ptrcmp, st_ptrhash);
1810  Ntk_NetworkForEachCombInput(network, gen, node) {
1811    st_insert(*tableOfLeaves, (char *)node, (char *) (long) (-1) );
1812  }
1813  return (numLatch);
1814}
1815
1816
1817/**Function********************************************************************
1818
1819  Synopsis [Computes image for incremental computation.]
1820
1821  Description [Computes image for  incremental computation.]
1822
1823  SideEffects []
1824
1825******************************************************************************/
1826static mdd_t *
1827IncrementalImageCompute(Ntk_Network_t *network,
1828                        Fsm_Fsm_t *fsm,
1829                        mdd_manager *mddManager,
1830                        mdd_t *fromLowerBound,
1831                        mdd_t *fromUpperBound,
1832                        mdd_t *toCareSet,
1833                        array_t *arrayOfRoots,
1834                        st_table *tableOfLeaves,
1835                        array_t *smoothVarArray,
1836                        array_t *relationArray,
1837                        int numLatch)
1838{
1839  Mvf_Function_t *function;
1840  mdd_t *relation, *optimizedRelation, *toCareSetRV, *imageRV;
1841  mdd_t  *subOptimizedRelation, *image;
1842  int mddId, i;
1843  array_t *arrayOfMvf;
1844  mdd_t *frontierSet;
1845
1846  frontierSet = bdd_between(fromLowerBound, fromUpperBound);
1847  /* Create the array of transition relations */
1848  toCareSetRV = mdd_substitute(mddManager, toCareSet,
1849                               fsm->fsmData.presentStateVars,
1850                               fsm->fsmData.nextStateVars);
1851
1852  arrayOfMvf = Ntm_NetworkBuildMvfs(network, arrayOfRoots,
1853                                    tableOfLeaves, frontierSet);
1854  for (i=0; i < numLatch; i++){
1855    function = array_fetch(Mvf_Function_t *, arrayOfMvf, i);
1856    mddId = array_fetch(int, fsm->fsmData.nextStateVars, i);
1857    /* Since both arrayOfMvf and fsmData have been obtained from */
1858    /* the same generator */
1859    relation = Mvf_FunctionBuildRelationWithVariable(function,
1860                                                     mddId);
1861    subOptimizedRelation = bdd_cofactor(relation, toCareSetRV);
1862    mdd_free(relation);
1863    optimizedRelation = bdd_cofactor(subOptimizedRelation, frontierSet);
1864    mdd_free(subOptimizedRelation);
1865    array_insert(mdd_t *, relationArray, i, optimizedRelation);
1866  }
1867  Mvf_FunctionArrayFree(arrayOfMvf);
1868  mdd_free(toCareSetRV);
1869  array_insert(mdd_t *, relationArray, numLatch, frontierSet);
1870  imageRV = Fsm_MddMultiwayAndSmooth(mddManager, relationArray,
1871                                     smoothVarArray);
1872  /*
1873  ** The above call can be substituted by more sophisticated
1874  ** Img_MultiwayLinearAndSmooth. However, that will have its
1875  ** associated overhead, and could offset any advantage. We
1876  ** expect that individual transition relation relations should
1877  ** be small and monolithic way to handle them would be ok.
1878  ** However, a good strategy would be find the quantification
1879  ** schedule which does not change with the computation of
1880  ** incremental transition relations.
1881  */
1882  for (i = 0; i <= numLatch; i++){
1883    mdd_free(array_fetch(mdd_t*, relationArray, i));
1884  }
1885  assert(CheckImageValidity(mddManager, imageRV,
1886                            fsm->fsmData.presentStateVars,
1887                            fsm->fsmData.inputVars));
1888  image = mdd_substitute(mddManager, imageRV,
1889                         fsm->fsmData.nextStateVars,
1890                         fsm->fsmData.presentStateVars);
1891  mdd_free(imageRV);
1892  assert(CheckImageValidity(mddManager, image,
1893                            fsm->fsmData.nextStateVars,
1894                            fsm->fsmData.inputVars));
1895  return image;
1896}
1897
1898/**Function********************************************************************
1899
1900  Synopsis [Prints information about onion rings]
1901
1902  Description [Prints information about onion rings.]
1903
1904  SideEffects []
1905
1906******************************************************************************/
1907static void
1908PrintOnionRings(Fsm_Fsm_t *fsm, int printStep,
1909                Fsm_RchType_t approxFlag, int nvars)
1910{
1911  int i;
1912  mdd_t *reachableStates;
1913  mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm);
1914  array_t *mintermVarArray = Fsm_FsmReadPresentStateVars(fsm);
1915
1916  fprintf(vis_stdout, "** rch warning: Not possible to compute size of reachable states at every iteration\n");
1917  if (Fsm_FsmReadReachabilityOnionRings(fsm) != NIL(array_t)) {
1918    arrayForEachItem(mdd_t *, Fsm_FsmReadReachabilityOnionRings(fsm),
1919                     i, reachableStates) {
1920      if (printStep && (i % printStep == 0)) {
1921        if (approxFlag != Fsm_Rch_Hd_c) {
1922          if (nvars <= 1023) {
1923            (void)fprintf(vis_stdout, "BFS step = %d\t|onion ring states| = %8g",
1924                          i, mdd_count_onset(mddManager, reachableStates,
1925                                             mintermVarArray));
1926            if (i != array_n(Fsm_FsmReadReachabilityOnionRings(fsm))-1) {
1927              fprintf(vis_stdout, "\n");
1928            } else {
1929              fprintf(vis_stdout, "\tSize = %d\n", mdd_size(reachableStates));
1930            }
1931
1932          } else {
1933            (void)fprintf(vis_stdout, "BFS step = %d\t|onion ring states| = ",
1934                          i);
1935            (void) bdd_print_apa_minterm(vis_stdout, reachableStates, nvars, (long)6);
1936            if (i != array_n(Fsm_FsmReadReachabilityOnionRings(fsm))-1) {
1937              fprintf(vis_stdout, "Final Size = %d\n", mdd_size(reachableStates));
1938            }
1939          }
1940        } else {
1941
1942          if (nvars <= 1023) {
1943            (void)fprintf(vis_stdout, "Step = %d\t|onion ring states| = %8g",
1944                          i, mdd_count_onset(mddManager, reachableStates,
1945                                             mintermVarArray));
1946            if (i != array_n(Fsm_FsmReadReachabilityOnionRings(fsm))-1) {
1947              fprintf(vis_stdout, "\n");
1948            } else {
1949              fprintf(vis_stdout, "\tSize = %d\n", mdd_size(reachableStates));
1950            }
1951          } else {
1952            (void)fprintf(vis_stdout, "Step = %d\t|onion ring states| = ",
1953                          i);
1954            (void) bdd_print_apa_minterm(vis_stdout, reachableStates, nvars, (long)6);
1955            if (i != array_n(Fsm_FsmReadReachabilityOnionRings(fsm))-1) {
1956              fprintf(vis_stdout, "Final Size = %d\n", mdd_size(reachableStates));
1957            }
1958          }
1959        }
1960      }
1961    }
1962  }
1963  return;
1964}/* printonionrings */
1965
1966/**Function********************************************************************
1967
1968  Synopsis [Reads in a sequence of integers separated by commas and
1969  stores them in an array.]
1970
1971  Description [Reads in a sequence of integers separated by commas from the
1972  environment variable guided_search_sequence.  It stores them in an array that
1973  it returns.  Alpha characters and 0 integers are replaced by
1974  -1.  Pads the remaining entries corresponding to the guide array with -1.
1975  Every number indicates the number of times the corresponding (in sequence)
1976  hint should be used.  The value -1 means `to convergence'.]
1977
1978
1979  SideEffects []
1980
1981******************************************************************************/
1982static array_t *
1983GenerateGuidedSearchSequenceArray(array_t *guideArray)
1984{
1985  char *seqStr = Cmd_FlagReadByName("guided_search_sequence");
1986  char *preStr;
1987  int intEntry;
1988  array_t *depthArray = array_alloc(int, 0);
1989  int i;
1990
1991  /* Skip parsing if we have no guided search sequence  */
1992  if (seqStr != NIL(char)  && strcmp(seqStr, "") != 0){
1993    preStr = strtok(seqStr, ",");
1994
1995    while(preStr != NIL(char)){
1996      intEntry = strtol(preStr, (char **) NULL, 10);
1997      array_insert_last(int, depthArray, (intEntry == 0 ? -1 : intEntry));
1998      preStr = strtok(NIL(char), ",");
1999    }
2000  }
2001
2002  if(array_n(depthArray) > array_n(guideArray)){
2003    fprintf(vis_stdout, "** rch warning: guided_search_sequence has more entries\n");
2004    fprintf(vis_stdout,"than there are hints.  Extra entires will be ignored\n");
2005  }
2006
2007  /* pad with -1s */
2008  for (i = array_n(depthArray); i < array_n(guideArray); i++) {
2009    array_insert_last(int, depthArray, -1);
2010  }
2011
2012  assert(array_n(depthArray) >= array_n(guideArray));
2013
2014  return depthArray;
2015}
2016
2017
2018/**Function********************************************************************
2019
2020  Synopsis [Computes the reachable states, frontier and fromUpperBound.]
2021
2022  Description [Computes the reachable states, frontier and
2023  fromUpperBound. For HD it also generates interior states, interior
2024  state candidates, dead-end residue, number of dead-ends, residue
2025  count, etc. For guided search, this procedure also generates a
2026  dead-end if the frontier is 0. Also this procedure keeps track of
2027  convergence and whether a dead-end is required at the end.]
2028
2029  SideEffects [All arguments are updated.]
2030
2031  SeeAlso [HdComputeReachabilityParameters FsmHdDeadEnd]
2032
2033******************************************************************************/
2034static void
2035ComputeReachabilityParameters(mdd_manager *mddManager,
2036                              Img_ImageInfo_t *imageInfo,
2037                              Fsm_RchType_t approxFlag,
2038                              mdd_t **reachableStates,
2039                              mdd_t **fromUpperBound,
2040                              mdd_t **fromLowerBound,
2041                              mdd_t **image,
2042                              FsmHdStruct_t *hdInfo,
2043                              mdd_t *initialStates,
2044                              array_t *mintermVarArray,
2045                              int *depth,
2046                              int printStep,
2047                              int shellFlag,
2048                              array_t *onionRings,
2049                              int verbosityLevel,
2050                              boolean guidedSearchMode,
2051                              mdd_t *hint,
2052                              int *hintDepth,
2053                              boolean *notConverged)
2054{
2055  if (approxFlag == Fsm_Rch_Bfs_c) {
2056    /* New set of reachable states is old set plus new states in image. */
2057    *reachableStates = AddStates(*fromLowerBound, *reachableStates,
2058                                 FSM_MDD_DONT_FREE, FSM_MDD_FREE);
2059    *fromUpperBound = *reachableStates;
2060
2061    /* in guided search, if the mode is to convergence or the
2062       limited depth has not been reached, and the frontier is empty,
2063       then generate a frontier in BFS mode (that is a full dead-end).  */
2064    if (guidedSearchMode &&
2065        mdd_is_tautology(*fromLowerBound, 0) /* no frontier */ &&
2066        (hdInfo->deadEndWithOriginalTR == FALSE) /* and guided search */ ) {
2067      assert(imageInfo != NIL(Img_ImageInfo_t));
2068      if (*hintDepth != 0) {
2069        /* add another onion ring. */
2070        if (shellFlag && onionRings) {
2071          mdd_t *temp = mdd_and(*fromLowerBound, *reachableStates, 1, 0);
2072          if (!mdd_is_tautology(temp, 0))
2073            array_insert_last(mdd_t *, onionRings, temp);
2074          else
2075            mdd_free(temp);
2076        }
2077        /* do a full dead-end (non-greedy), compute all the frontier states */
2078        mdd_free(*fromLowerBound);
2079        *fromLowerBound = FsmHdDeadEnd(mddManager, imageInfo, *reachableStates,
2080                                       hdInfo,
2081                                       mintermVarArray,
2082                                       FSM_HD_NONGREEDY, verbosityLevel);
2083        mdd_free(hdInfo->interiorStates);
2084        hdInfo->interiorStates = NIL(mdd_t);
2085        *reachableStates = AddStates(*fromLowerBound, *reachableStates,
2086                                     FSM_MDD_DONT_FREE, FSM_MDD_FREE);
2087        *fromUpperBound = *reachableStates;
2088        (*hintDepth)--;
2089        (*depth)++;
2090        if (mdd_is_tautology(hint, 1)) hdInfo->deadEndWithOriginalTR = TRUE;
2091      } else {
2092        *notConverged = TRUE;
2093        /* set this flag for correct detection of convergence
2094           Corner case: when limited depth and frontier = 0 */
2095      }
2096    }
2097  } else if (approxFlag == Fsm_Rch_Hd_c) {
2098    assert(imageInfo != NIL(Img_ImageInfo_t));
2099      if (!guidedSearchMode || (*hintDepth != 0)) {
2100        /* computes reachable states, fromLowerBound and fromUpperBound.
2101         * Updates all other quantities such as interiorStates,
2102         * deadEndResidue. */
2103        HdComputeReachabilityParameters(mddManager, imageInfo,
2104                                        reachableStates,
2105                                        fromUpperBound,
2106                                        fromLowerBound,
2107                                        image,
2108                                        hdInfo,
2109                                        initialStates,
2110                                        mintermVarArray,
2111                                        depth, printStep,
2112                                        shellFlag, onionRings,
2113                                        verbosityLevel);
2114        if (guidedSearchMode) (*hintDepth)--;
2115
2116      } else { /* guidedSearchMode and hint depth is 0 */
2117        if (mdd_is_tautology(*fromLowerBound, 0)) {
2118          *notConverged = TRUE;
2119        /* set this flag for correct detection of convergence
2120           Corner case: when limited depth and frontier = 0 */
2121        }
2122        /* add another onion ring. */
2123        if (shellFlag && onionRings) {
2124          mdd_t *temp = mdd_and(*fromLowerBound, *reachableStates, 1, 0);
2125          if (!mdd_is_tautology(temp, 0))
2126            array_insert_last(mdd_t *, onionRings, temp);
2127          else
2128            mdd_free(temp);
2129        }
2130
2131      }
2132  }
2133  return;
2134} /* End of ComputeReachabilityParameters */
Note: See TracBrowser for help on using the repository browser.