Example #1
0
/**Function********************************************************************

  Synopsis           [Complete trace re-execution]

  Description [Complete trace re-execution.  In order to be run, the
  trace must be complete w.r.t. master fsm language. Returns 0 if a
  trace is executed successfully, and 1 otherwise.]

  SideEffects        [None]

  SeeAlso            []

******************************************************************************/
int Trace_execute_trace(const Trace_ptr trace,
                        const CompleteTraceExecutor_ptr executor)
{
    boolean success = true;

    TRACE_CHECK_INSTANCE(trace);
    COMPLETE_TRACE_EXECUTOR_CHECK_INSTANCE(executor);

    SexpFsm_ptr sexp_fsm =  \
                            PropDb_master_get_scalar_sexp_fsm(PropPkg_get_prop_database());

    SEXP_FSM_CHECK_INSTANCE(sexp_fsm);

    if (!Trace_is_complete(trace, SexpFsm_get_vars_list(sexp_fsm), true)) {
        fprintf(nusmv_stderr, "Error: cannot execute incomplete trace.\n");
        success = false;
    }

    else {
        if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) {
            fprintf(nusmv_stderr,
                    "Executing trace of length %d\n", Trace_get_length(trace));
        }

        /* execute the trace using given executor. */
        success = CompleteTraceExecutor_execute(executor, trace, NIL(int));
    }

    return success ? 0 : 1;
}
Example #2
0
/**Function********************************************************************

  Synopsis           [Partial trace re-execution and fill-in]

  Description        [Partial trace re-execution and fill-in.

                      Tries to complete the given trace using the
                      given incomplete trace executor.  If successful,
                      a complete trace is registered into the Trace
                      Manager.

                      0 is returned if trace could be succesfully completed.
                      1 is returned otherwise]

  SideEffects        [None]

  SeeAlso            []

******************************************************************************/
int Trace_execute_partial_trace(const Trace_ptr trace,
                                const PartialTraceExecutor_ptr executor,
                                const NodeList_ptr language)
{
    boolean success = true;

    TRACE_CHECK_INSTANCE(trace);
    PARTIAL_TRACE_EXECUTOR_CHECK_INSTANCE(executor);
    NODE_LIST_CHECK_INSTANCE(language);

    if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) {
        fprintf(nusmv_stderr,
                "Executing trace of length %d\n", Trace_get_length(trace));
    }

    {   /* execute a partial trace using given executor, register complete
           trace upon succesful completion */
        Trace_ptr complete_trace = \
                                   PartialTraceExecutor_execute(executor, trace, language, NIL(int));

        if (TRACE(NULL) != complete_trace) {
            int trace_id = \
                           TraceManager_register_trace(TracePkg_get_global_trace_manager(),
                                   complete_trace);
            fprintf(nusmv_stdout,
                    "-- New complete trace is stored at %d index.\n",
                    1 + trace_id);
        }
        else {
            success = false;
        }
    }

    return success ? 0 : 1;
}
Example #3
0
Trace_ptr
Bmc_fill_trace_from_cnf_model(const BeEnc_ptr be_enc,
                              const Slist_ptr cnf_model,
                              int k, Trace_ptr trace)
{
  TraceIter first;
  /* local refs */
  const NuSMVEnv_ptr env = EnvObject_get_environment(ENV_OBJECT(be_enc));
  const ExprMgr_ptr exprs = EXPR_MGR(NuSMVEnv_get_value(env, ENV_EXPR_MANAGER));
  const BoolEnc_ptr bool_enc = \
    BoolEncClient_get_bool_enc(BOOL_ENC_CLIENT(be_enc));
  const NodeMgr_ptr nodemgr =
    NODE_MGR(NuSMVEnv_get_value(env, ENV_NODE_MGR));

  const Be_Manager_ptr be_mgr = BeEnc_get_be_manager(be_enc);
  const SymbTable_ptr st = BaseEnc_get_symb_table(BASE_ENC(be_enc));

  hash_ptr tvar_2_bval = new_assoc();
  hash_ptr time_2_step = new_assoc();

  Siter genLiteral;
  nusmv_ptrint cnfLiteral;
  nusmv_ptrint beLiteral;

  int i;

  TRACE_CHECK_INSTANCE(trace);
  nusmv_assert(Trace_is_empty(trace));

  first = Trace_first_iter(trace);

  /* phase 0: setup trace iterators for all times */
  insert_assoc(time_2_step, NODE_FROM_INT(0), (node_ptr)(first));
  for (i = 1; i <= k; ++ i) {
    TraceIter step = Trace_append_step(trace);
    insert_assoc(time_2_step, NODE_FROM_INT(i), (node_ptr)(step));
  }

  /* phase 1: we consider only the cnf variables corresponding to BE
     variables in the range [0, k].

     Thus we ignore the cnf variables that are not corresponding to
     the encoding of the:
     - model variables;
     - encoding variables (sub formulas, loop variables, ...)
  */
  SLIST_FOREACH(cnf_model, genLiteral) {
    int var_idx, ut_index, vtime;
    node_ptr var, key;

    cnfLiteral = (nusmv_ptrint) Siter_element(genLiteral);
    beLiteral = (nusmv_ptrint) Be_CnfLiteral2BeLiteral(be_mgr, cnfLiteral);

    /* if there is no corresponding rbc variable skip this */
    if (0 == beLiteral) continue;

    /* get timed var */
    var_idx = Be_BeLiteral2BeIndex(be_mgr, beLiteral);
    ut_index = BeEnc_index_to_untimed_index(be_enc, var_idx);
    vtime = BeEnc_index_to_time(be_enc, var_idx);
    var = BeEnc_index_to_name(be_enc, ut_index);

    /* needed to adapt to new trace timing format, input is stored
     in the next step */
    if (SymbTable_is_symbol_input_var(st, var)) { ++ vtime; }

    if (vtime > k) continue;

    /* if it's a bit get/create a BitValues structure for
       the scalar variable which this bit belongs */
    if (BoolEnc_is_var_bit(bool_enc, var)) {
      node_ptr scalar_var = BoolEnc_get_scalar_var_from_bit(bool_enc, var);
      BitValues_ptr bv;
      key = find_node(nodemgr, ATTIME, scalar_var, NODE_FROM_INT(vtime));

      bv = BIT_VALUES(find_assoc(tvar_2_bval, key));
      if (BIT_VALUES(NULL) == bv) {
        bv = BitValues_create(bool_enc, scalar_var);
        insert_assoc(tvar_2_bval, key, (node_ptr)(bv));
      }

      /* set the bit value */
      BitValues_set(bv, BoolEnc_get_index_from_bit(bool_enc, var),
                    (beLiteral >= 0) ? BIT_VALUE_TRUE : BIT_VALUE_FALSE);

    }
    else { /* boolean variables do not require any further processing */

      TraceIter timed_step = (-1 != vtime) /* frozenvars */
        ? TRACE_ITER(find_assoc(time_2_step, NODE_FROM_INT(vtime)))
        : first ;

      nusmv_assert(TRACE_END_ITER != timed_step);
      Trace_step_put_value(trace, timed_step, var, beLiteral >= 0
                           ? ExprMgr_true(exprs) : ExprMgr_false(exprs));
    }

  } /* SLIST_FOREACH (phase 1) */
Example #4
0
/**Function********************************************************************

  Synopsis           [SAT Based Incremental simulation]

  Description        [This function performs incremental sat based
  simulation up to <tt>target_steps</tt>.

  Simulation starts from an initial state internally selected.

  It accepts a constraint to direct the simulation to paths satisfying
  such constraints. The constraints is assumed to be over state, input
  and next state variables. Thus, please carefully consider this
  information while providing constraints to this routine.

  The simulation stops if either the <tt>target_steps</tt> steps of
  simulation have been performed, or the simulation bumped in a
  deadlock (that might be due to the constraints that are too strong).

  Parameters:

  'print_trace'  : shows the generated trace
  'changes_only' : shows only variables that actually change value
  between one step and it's next one]

  SideEffects        [The possibly partial generated simulaiton trace
  is added to the trace manager for possible reuse.]

  SeeAlso            [optional]

******************************************************************************/
int Bmc_StepWiseSimulation(BeFsm_ptr be_fsm,
                           BddEnc_ptr bdd_enc,
                           TraceManager_ptr trace_manager,
                           int target_steps,
                           be_ptr constraints,
                           boolean time_shift,
                           boolean print_trace,
                           boolean changes_only,
                           Simulation_Mode mode,
                           boolean display_all)
{
#if NUSMV_HAVE_INCREMENTAL_SAT
  int steps;
  boolean no_deadlock;
  BeEnc_ptr be_enc = BE_ENC(NULL);
  Be_Manager_ptr be_mgr = (Be_Manager_ptr)NULL;
  SatIncSolver_ptr solver = SAT_INC_SOLVER(NULL);
  SatSolverGroup satGrp = (SatSolverGroup)-1;
  SatSolverResult satResult = SAT_SOLVER_UNAVAILABLE;
  Trace_ptr trace = bmc_simulate_get_curr_sim_trace();
  int tr_num = bmc_simulate_get_curr_sim_trace_index();
  be_ptr be_trans = (be_ptr)NULL;
  long time_statistics = util_cpu_time();

  TRACE_CHECK_INSTANCE(trace); /* a trace was picked */

  if (target_steps <= 0) return -1;

  /* Create the SAT solver instance */
  solver  = Sat_CreateIncSolver(get_sat_solver(OptsHandler_get_instance()));
  if (SAT_INC_SOLVER(NULL) == solver) {
    fprintf(nusmv_stderr,
            "Incremental sat solver '%s' is not available.\n",
            get_sat_solver(OptsHandler_get_instance()));
    return -1;
  }

  switch (mode) {
  case Random:
    bmc_simulate_enable_random_mode(SAT_SOLVER(solver));
    break;
  case Interactive:
    /* Do nothing */
    break;
  case Deterministic:
    /* Do nothing */
    break;
  default:
    internal_error("%s: Invalid mode given", __func__);
  }

  no_deadlock = true;

  be_enc = BeFsm_get_be_encoding(be_fsm);
  be_mgr = BeEnc_get_be_manager(be_enc);

  /* 1. Add the transition relation into the solver permanently */
  be_trans = BeFsm_get_invar(be_fsm);
  be_trans = Be_And(be_mgr,
                    be_trans,
                    BeEnc_shift_curr_to_next(be_enc, be_trans));
  be_trans = Be_And(be_mgr, BeFsm_get_trans(be_fsm), be_trans);

  /* We force the constraints that can be over starting states, or
     over next states, or over the input. If the constraint is over
     the current state variables, then it might be the case the chosen
     next statre does not satisfy the constraint. */
  if (time_shift) {
    constraints = BeEnc_shift_curr_to_next(be_enc, constraints);
  }

  be_trans = Be_And(be_mgr, be_trans, constraints);

  /* Necessary to re-use the routines for extracting the model */
  be_trans = BeEnc_untimed_expr_to_timed(be_enc, be_trans, 0);
  bmc_simulate_add_be_into_inc_solver_positively(SAT_INC_SOLVER(solver),
                      SatSolver_get_permanent_group(SAT_SOLVER(solver)),
                      be_trans, be_enc);

  /* 2. Iteration adding last computed state as src state and
        extracting the pair (input,next_state), adding the pair to the
        computed trace, and then iterating from the so far computed
        next_state */
  {
    for (steps = 0; ((steps < target_steps) && no_deadlock) ; steps++) {
      be_ptr be_src_state = (be_ptr)NULL;

      if (opt_verbose_level_gt(OptsHandler_get_instance(), 1)) {
        fprintf(nusmv_stderr, "Performing simulation step %d ...", steps+1);
      }

      /* 2.0. Extraction from the so far compute trace the last
         state. */
      be_src_state = BeEnc_untimed_expr_to_timed(be_enc,
                         TraceUtils_fetch_as_be(trace, Trace_last_iter(trace),
                                        TRACE_ITER_SF_VARS, be_enc, bdd_enc), 0);

      /* 2.2 Create the group to store the last state and, add the
           last state to the solver */
      satGrp = SatIncSolver_create_group(solver);
      bmc_simulate_add_be_into_inc_solver_positively(SAT_INC_SOLVER(solver),
                                                     satGrp,
                                                     be_src_state, be_enc);

      /* 2.3. Call the solver on the instantiated problem */
      satResult = SatSolver_solve_all_groups(SAT_SOLVER(solver));

      switch (satResult) {
      case SAT_SOLVER_SATISFIABLE_PROBLEM:
        if (Interactive == mode) {
          Trace_ptr iTrace =
            bmc_simulate_interactive_step(SAT_SOLVER(solver), be_enc,
                                          bdd_enc, Trace_get_symbols(trace),
                                          true, display_all);
          Trace_concat(trace, &iTrace);
        }
        else {
          /* Append current computed state to the trace */
          bmc_trace_utils_append_input_state(trace, be_enc,
                                   SatSolver_get_model(SAT_SOLVER(solver)));
        }

        break;

      case SAT_SOLVER_UNSATISFIABLE_PROBLEM:
        fprintf(nusmv_stderr,
            "The model reached a deadlock state: iteration %d.\n", steps);
        if (!Be_IsTrue(be_mgr, constraints)) {
          fprintf(nusmv_stderr,
            "This might be due to the constraints that are too strong.\n");
        }
        no_deadlock = false;
        break;

      default:
        fprintf(nusmv_stderr,
            "At iteration %d, the solver returned an unexpected value: %d\n",
                steps, satResult);
        no_deadlock = false;
        break;
      }

      /* 2.4. Remove and destroy the group containing the last
              computed state */
      SatIncSolver_destroy_group(solver, satGrp);

      if (opt_verbose_level_gt(OptsHandler_get_instance(), 1)) {
        fprintf(nusmv_stderr, "... done\n");
      }

      if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) {
        fprintf(nusmv_stdout,
                " -- simulation of step %d has finished in %2.1f seconds\n",
                steps, (util_cpu_time() - time_statistics) / 1000.0);
        time_statistics = util_cpu_time();
      }
    } /* (steps < target_steps) && no_deadlock) */

  } /* iteration block */

  /* 3. We clean the memory and we return */
  SatIncSolver_destroy(solver);

  if (no_deadlock && print_trace) {
    TraceManager_execute_plugin(trace_manager, TRACE_OPT(NULL),
                                (changes_only) ? 0 : 1, tr_num);
  }

  return steps;

#else
  fprintf(nusmv_stderr,
          "%s: Relies on Incremental solving. "
          "No incremental SAT solver is available now\n", __func__);
  return -1;
#endif
}
Example #5
0
/**Function********************************************************************

   Synopsis           [Performs simulation]

   Description [Generate a problem with no property, and search for a
   solution, appending it to the current simulation trace.
   Returns 1 if solver could not be created, 0 if everything went smooth]

   SideEffects        [None]

   SeeAlso            []

******************************************************************************/
int Bmc_Simulate(const BeFsm_ptr be_fsm, BddEnc_ptr bdd_enc,
                 be_ptr be_constraints, boolean time_shift,
                 const int k, const boolean print_trace,
                 const boolean changes_only,
                 const Simulation_Mode mode)
{
  be_ptr init, prob; /* The problem in BE format */
  SatSolver_ptr solver;
  SatSolverResult sat_res;
  BeEnc_ptr be_enc;
  Be_Manager_ptr be_mgr;
  Be_Cnf_ptr cnf;

  Trace_ptr trace = bmc_simulate_get_curr_sim_trace();
  int tr_num = bmc_simulate_get_curr_sim_trace_index();

  TRACE_CHECK_INSTANCE(trace); /* curr trace was picked */

  be_enc = BeFsm_get_be_encoding(be_fsm);
  be_mgr = BeEnc_get_be_manager(be_enc);

  if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) {
    fprintf(nusmv_stderr, "Simulation of length %d (no loopback)\n", k);
  }

  solver = Sat_CreateNonIncSolver(get_sat_solver(OptsHandler_get_instance()));
  if (solver == SAT_SOLVER(NULL)) {
    fprintf(nusmv_stderr,
            "Non-incremental sat solver '%s' is not available.\n",
            get_sat_solver(OptsHandler_get_instance()));
    return 1;
  }

  switch (mode) {
  case Random:
    bmc_simulate_enable_random_mode(SAT_SOLVER(solver));
    break;
  case Interactive:
    internal_error("%s: Interactive mode not supported yet", __func__);
    break;
  case Deterministic:
    /* Do nothing */
    break;
  default:
    internal_error("%s: Invalid mode given", __func__);
  }

  /* starting state taken from the last node of the current sim trace */
  init = BeEnc_untimed_expr_to_timed(be_enc,
               TraceUtils_fetch_as_be(trace, Trace_last_iter(trace),
                                      TRACE_ITER_SF_VARS, be_enc, bdd_enc), 0);

  prob = Be_And(be_mgr, Bmc_Model_GetPathNoInit(be_fsm, k), init);

  /* Use constraints only if actually necessary */
  if (!Be_IsTrue(be_mgr, be_constraints)) {
    int i;
    for (i = 0; i <= k; ++i) {
      be_ptr be_timed = be_constraints;

      if (time_shift) {
        be_timed = BeEnc_shift_curr_to_next(be_enc, be_timed);
      }

      be_timed = BeEnc_untimed_expr_to_timed(be_enc, be_timed, i);

      prob = Be_And(be_mgr, prob, be_timed);
    }
  }

  prob = Bmc_Utils_apply_inlining(be_mgr, prob);
  cnf = Be_ConvertToCnf(be_mgr, prob, 1);

  SatSolver_add(solver, cnf, SatSolver_get_permanent_group(solver));
  SatSolver_set_polarity(solver, cnf, 1,
                         SatSolver_get_permanent_group(solver));
  sat_res = SatSolver_solve_all_groups(solver);

  /* Processes the result: */
  switch (sat_res) {

  case SAT_SOLVER_UNSATISFIABLE_PROBLEM:
    fprintf(nusmv_stdout,
            "The model deadlocks before requested length %d!\n", k);
    break;

  case SAT_SOLVER_SATISFIABLE_PROBLEM:
    {
      BoolSexpFsm_ptr bsexp_fsm; /* needed for trace language */
      bsexp_fsm =  \
        PropDb_master_get_bool_sexp_fsm(PropPkg_get_prop_database());
      BOOL_SEXP_FSM_CHECK_INSTANCE(bsexp_fsm);

      Trace_ptr extension = \
        Bmc_create_trace_from_cnf_model(be_enc,
             SexpFsm_get_symbols_list(SEXP_FSM(bsexp_fsm)), NIL(char),
                                      TRACE_TYPE_UNSPECIFIED,
                                      SatSolver_get_model(solver), k);

      trace = Trace_concat(trace, &extension);
      nusmv_assert(TRACE(NULL) == extension);

      if (print_trace) {
        TraceManager_execute_plugin(global_trace_manager, TRACE_OPT(NULL),
                                    (changes_only) ? 0 : 1, tr_num);
      }

      break;
    } /* SAT */

  case SAT_SOLVER_INTERNAL_ERROR:
    internal_error("Sorry, solver answered with a fatal Internal "
                   "Failure during problem solving.\n");

  case SAT_SOLVER_TIMEOUT:
  case SAT_SOLVER_MEMOUT:
    internal_error("Sorry, solver ran out of resources and aborted "
                   "the execution.\n");

  default:
    internal_error(" Bmc_Simulate: Unexpected value in sat result");
  } /* switch */

  /* cleanup */
  SatSolver_destroy(solver);
  Be_Cnf_Delete(cnf);

  return 0;
}
/**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;
}