/**Function********************************************************************

  Synopsis [Executes a trace on the fsm given at construction time
  using BDDs]

  Description [The trace is executed using BDDs, that is a proof that
  the fsm is compatible with the trace is built (if such proof
  exists). Incomplete traces are filled-in with compatible values for
  state and input variables.

  Given trace can be either complete or incomplete.

  The number of performed steps (transitions) is returned in *n_steps,
  if a non-NULL pointer is given. If the initial state is not
  compatible -1 is written.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
static Trace_ptr
bdd_partial_trace_executor_execute
(const PartialTraceExecutor_ptr partial_executor, const Trace_ptr trace,
 const NodeList_ptr language, int* n_steps)
{
  /* local references to self */
  const BDDPartialTraceExecutor_ptr self = \
    BDD_PARTIAL_TRACE_EXECUTOR(partial_executor);

  const BaseTraceExecutor_ptr executor = \
    BASE_TRACE_EXECUTOR(partial_executor);

  Trace_ptr res = TRACE(NULL); /* failure */

  int count = -1;
  boolean success = true;

  DdManager* dd;
  BddStates trace_states;
  TraceIter step = TRACE_END_ITER;

  BddStates fwd_image = (BddStates) NULL;
  node_ptr path = Nil; /* forward constrained images will be used
                          later to compute the complete trace */

  const char* trace_description = "BDD Execution";

  /* 0- Check prerequisites */
  BDD_PARTIAL_TRACE_EXECUTOR_CHECK_INSTANCE(self);
  TRACE_CHECK_INSTANCE(trace);
  BDD_FSM_CHECK_INSTANCE(self->fsm);
  BDD_ENC_CHECK_INSTANCE(self->enc);

  dd = BddEnc_get_dd_manager(self->enc);

  step = trace_first_iter(trace);
  nusmv_assert(TRACE_END_ITER != step);

  trace_states = TraceUtils_fetch_as_bdd(trace, step,
                                         TRACE_ITER_SF_SYMBOLS, self->enc);

  /* 1- Check Start State */
  {
    bdd_ptr init_bdd = BddFsm_get_init(self->fsm);
    bdd_ptr invar_bdd = BddFsm_get_state_constraints(self->fsm);
    BddStates source_states; /* last known states */

    source_states = bdd_and(dd, init_bdd, invar_bdd);
    bdd_and_accumulate(dd, &source_states, trace_states);

    bdd_free(dd, invar_bdd);
    bdd_free(dd, init_bdd);
    bdd_free(dd, trace_states);

    if (!bdd_is_false(dd, source_states)) {

      boolean terminate = false;
      path = cons(NODE_PTR(bdd_dup(source_states)), Nil);

      ++ count;

      /* 2- Check Consecutive States are related by transition relation */
      do {
        BddStates last_state; /* (unshifted) next state */
        BddStates next_state; /* next state constraints */

        BddInputs next_input; /* next input constraints */
        BddStatesInputsNexts next_combo; /* state-input-next constraints */

        BddStatesInputsNexts constraints;

        step = TraceIter_get_next(step);
        if (TRACE_END_ITER != step) {

          next_input = \
            TraceUtils_fetch_as_bdd(trace, step, TRACE_ITER_I_SYMBOLS,
                                    self->enc);
          next_combo = \
            TraceUtils_fetch_as_bdd(trace, step, TRACE_ITER_COMBINATORIAL,
                                    self->enc);
          last_state = \
            TraceUtils_fetch_as_bdd(trace, step, TRACE_ITER_SF_SYMBOLS,
                                    self->enc);

          next_state = BddEnc_state_var_to_next_state_var(self->enc, last_state);

          if (0 < BaseTraceExecutor_get_verbosity(executor)) {
            fprintf(BaseTraceExecutor_get_output_stream(executor),
                    "-- executing step %d ... ", 1 + count);
            fflush(BaseTraceExecutor_get_output_stream(executor));
          }

          /* building constrained fwd image */
          constraints = bdd_and(dd, next_input, next_combo);
          bdd_and_accumulate(dd, &constraints, next_state);

          fwd_image =
            BddFsm_get_sins_constrained_forward_image(self->fsm, source_states,
                                                      constraints);

           /* test whether the constrained fwd image is not empty */
          if (!bdd_is_false(dd, fwd_image)) {
            if (0 < BaseTraceExecutor_get_verbosity(executor)) {
              fprintf(BaseTraceExecutor_get_output_stream(executor), "done\n");
            }
            path = cons(NODE_PTR(fwd_image), path);
            ++ count;
          }
          else {
            if (0 < BaseTraceExecutor_get_verbosity(executor)) {
              fprintf(BaseTraceExecutor_get_output_stream(executor),
                      "failed!\n");
            }
            terminate = true;
            success = false;
          }

          /* no longer used bdd refs */
          bdd_free(dd, next_input);
          bdd_free(dd, next_combo);
          bdd_free(dd, last_state);
          bdd_free(dd, next_state);

          bdd_free(dd, source_states);
          source_states = bdd_dup(fwd_image);
        }

        else {
          if (0 == count) {
            fprintf(BaseTraceExecutor_get_error_stream(executor),
                    "Warning: trace has no transitions.\n");
          }
          terminate = true;
        }
      } while (!terminate); /* loop on state/input pairs */
    } /* if has initial state */

    else {
      fprintf(BaseTraceExecutor_get_error_stream(executor),
              "Error: starting state is not initial state.\n");
      success = false;
    }

    /* 3- If last state could be reached a complete trace exists */
    if (success) {
      if (0 < count) {
        res = \
          bdd_partial_trace_executor_generate(self, fwd_image, path,
                                              count, language,
                                              trace_description);
      }

      else { /* generates a complete state of trace of length 0 */
        res = \
          bdd_partial_trace_executor_generate(self, source_states,
                                              Nil, 0, language,
                                              trace_description);
      }

      nusmv_assert(TRACE(NULL) != res);

      /* cleanup */
      walk_dd(dd, bdd_free, path);
      free_list(path);
    }

    bdd_free(dd, source_states);
  }

  /* as a final stage, verify loopbacks consistency using internal
     service. The incomplete trace is compatible (that is, a valid
     completion exists) iff exactly len(Trace) steps have been
     performed *and* loopback data for the incomplete trace applies to
     the complete one as well. */
  if (TRACE(NULL) != res) {
    if (Trace_get_length(trace) == count &&
        partial_trace_executor_check_loopbacks(partial_executor, trace, res)) {

      fprintf(BaseTraceExecutor_get_output_stream(executor),
              "-- Trace was successfully completed.\n");
    }

    else {
      Trace_destroy(res);
      res = TRACE(NULL);
    }
  }

  if (TRACE(NULL) == res) {
    fprintf(BaseTraceExecutor_get_output_stream(executor),
            "-- Trace could not be completed.\n");
  }

  if (NIL(int) != n_steps) { *n_steps = count; }
  return res;
}
Example #2
0
int Compass_write_sigref(NuSMVEnv_ptr env,
                         BddFsm_ptr fsm,
                         FILE* sigref_file,
                         FILE* prob_file, /* can be NULL */
                         FILE* ap_file, /* can be NULL */
                         Expr_ptr tau, /* can be NULL */
                         boolean do_indent /* Beautify the XML output */
                         )
{
  BddEnc_ptr enc = BddFsm_get_bdd_encoding(fsm);
  DDMgr_ptr dd = BddEnc_get_dd_manager(enc);
  const NodeMgr_ptr nodemgr =
    NODE_MGR(NuSMVEnv_get_value(env, ENV_NODE_MGR));
  const TypeChecker_ptr tc = BaseEnc_get_type_checker(BASE_ENC(enc));

  NodeList_ptr ap_list_add = NODE_LIST(NULL);
  NodeList_ptr probs_list = NULL;
  NodeList_ptr ap_list = NULL;
  int retval = 0;

  add_ptr prob_add;
  add_ptr init_add;
  add_ptr trans_add;
  add_ptr tau_add;
  bdd_ptr bdd_trans;
  bdd_ptr state_mask = NULL;
  bdd_ptr input_mask = NULL;
  bdd_ptr next_state_mask = NULL;
  bdd_ptr next_and_curr_state_mask = NULL;

  /* preprocessing of the parameters */
  /* tau */
  if (EXPR(NULL) != tau) {
    tau = Compile_FlattenSexp(BaseEnc_get_symb_table(BASE_ENC(enc)),
                              car(tau) /* gets rid of SIMPWFF */,
                              Nil);
  }

  /* prob_file */
  if (NULL != prob_file) {
    ParserProb_ptr pl_parser = NULL;

    pl_parser = ParserProb_create(env);
    ParserProb_parse_from_file(pl_parser, prob_file);
    probs_list = ParserProb_get_prob_list(pl_parser);

    if (NODE_LIST(NULL) != probs_list) {
      Compass_check_prob_list(tc, probs_list);
    }

    ParserProb_destroy(pl_parser);
  }

  /* ap_file */
  if (NULL != ap_file) {
    ParserAp_ptr ap_parser = NULL;

    ap_parser = ParserAp_create(env);
    ParserAp_parse_from_file(ap_parser, ap_file);

    ap_list = ParserAp_get_ap_list(ap_parser);

    if (NODE_LIST(NULL) != ap_list) {
      Compass_check_ap_list(tc, ap_list);
    }

    ParserAp_destroy(ap_parser);
  }

  /* collects all required pieces */

  state_mask = BddEnc_get_state_frozen_vars_mask_bdd(enc);
  input_mask = BddEnc_get_input_vars_mask_bdd(enc);
  next_state_mask = BddEnc_state_var_to_next_state_var(enc, state_mask);
  next_and_curr_state_mask = bdd_and(dd, state_mask, next_state_mask);

  { /* calculates the initial states */
    bdd_ptr bdd_init = BddFsm_get_init(fsm);
    bdd_ptr bdd_sinvar = BddFsm_get_state_constraints(fsm);
    bdd_ptr bdd_iinvar = BddFsm_get_input_constraints(fsm);
    bdd_and_accumulate(dd, &bdd_init, bdd_sinvar);
    bdd_and_accumulate(dd, &bdd_init, bdd_iinvar);
    bdd_and_accumulate(dd, &bdd_init, state_mask);

    init_add = bdd_to_add(dd, bdd_init);

    bdd_free(dd, bdd_iinvar);
    bdd_free(dd, bdd_sinvar);
    bdd_free(dd, bdd_init);
  }


  { /* to control dynamic reordering */
    dd_reorderingtype method;
    int dd_reord_status;

    /* Dynamic reordering during monolithic trans can improve performances */
    dd_reord_status = dd_reordering_status(dd, &method);
    dd_autodyn_enable(dd, method);

    { /* calculates the transition relation */
      bdd_ptr bdd_sinvar = BddFsm_get_state_constraints(fsm);
      bdd_ptr bdd_nsinvar = BddEnc_state_var_to_next_state_var(enc, bdd_sinvar);
      bdd_ptr bdd_iinvar = BddFsm_get_input_constraints(fsm);

      bdd_trans = BddFsm_get_monolithic_trans_bdd(fsm);
      bdd_and_accumulate(dd, &bdd_trans, bdd_sinvar);
      bdd_and_accumulate(dd, &bdd_trans, bdd_nsinvar);
      bdd_and_accumulate(dd, &bdd_trans, bdd_iinvar);
      bdd_and_accumulate(dd, &bdd_trans, next_and_curr_state_mask);
      bdd_and_accumulate(dd, &bdd_trans, input_mask);

/* #define DEBUG_TRANS */
#ifdef DEBUG_TRANS
      FILE * p = stdout; // fopen("TRANS.txt", "w");
      fprintf(p, "==================================================\n");
      fprintf(p, "TRANS\n");
      fprintf(p, "==================================================\n");
      // print_trans(enc, bdd_trans, p);
      dd_printminterm(dd, bdd_trans);
      fprintf(p, "==================================================\n");
      dd_printminterm(dd, input_mask);
      fprintf(p, "==================================================\n");
      // fclose(p);
#endif

      trans_add = bdd_to_add(dd, bdd_trans);

      bdd_free(dd, bdd_iinvar);
      bdd_free(dd, bdd_nsinvar);
      bdd_free(dd, bdd_sinvar);
    }

    /* Dynamic reordering is disabled after monolitic
       construction. Later it will be re-enabled if it was enable
       before entering this block */
    dd_autodyn_disable(dd);

    /* probability and tau are optional */
    if (probs_list != NODE_LIST(NULL)) {
      prob_add = Compass_process_prob_list(enc, probs_list, bdd_trans);
    }
    else prob_add = (add_ptr) NULL;

    bdd_free(dd, bdd_trans);

    if (tau != (Expr_ptr) NULL) {
      tau_add = BddEnc_expr_to_add(enc, tau, Nil);

      /* [RC]: This code was disable because it seems masks for input
       * var do not work */
      /* mask_tau_add = BddEnc_apply_input_vars_mask_add(enc, tau_add); */
      /* add_free(dd, tau_add); */
      /* tau_add = mask_tau_add; */
    }
    else
      tau_add = (add_ptr) NULL;

    if (NODE_LIST(NULL) != ap_list) {
      add_ptr expr_add, expr_add_mask;
      ListIter_ptr iter;
      ap_list_add = NodeList_create();

      NODE_LIST_FOREACH(ap_list, iter) {
        node_ptr ap_el = (node_ptr)NodeList_get_elem_at(ap_list, iter);
        node_ptr lab = car(ap_el);
        node_ptr expr = cdr(ap_el);

        expr_add = BddEnc_expr_to_add(enc, expr, Nil);
        expr_add_mask = BddEnc_apply_state_frozen_vars_mask_add(enc, expr_add);
        NodeList_append(ap_list_add, cons(nodemgr, lab, (node_ptr)expr_add_mask));
        add_free(dd, expr_add);
        /* The expr_add_mask will be freed later when the ap_list_add
           will be destroyed */
      }
    }