/**
 * Compute the image of a set of states.
 */
BDD BddTrAttachment::img(const BDD& from) const
{
  BDD imgy = from.ExistAbstract(_prequantx);
  for (vector< RelPart >::const_iterator it = _tr.begin();
       it != _tr.end(); ++it) {
    imgy = imgy.AndAbstract(it->part(), it->fwQuantCube());
  }
  BDD imgx = imgy.SwapVariables(_xvars,_yvars);
  return imgx;

} // BddTrAttachment::img
/**
 * Compute the preimage of a set of states.
 */
BDD BddTrAttachment::preimg(const BDD& from) const
{
  BDD preimgx = from.SwapVariables(_yvars,_xvars);
  preimgx = preimgx.ExistAbstract(_prequanty);
  for (vector< RelPart >::const_iterator it = _tr.begin();
       it != _tr.end(); ++it) {
    preimgx = preimgx.AndAbstract(it->part(), it->bwQuantCube());
  }
  return preimgx;

} // BddTrAttachment::preimg
Exemple #3
0
BDD Synth::pre_sys(BDD dst) {
    /**
    Calculate predecessor states of given states.

        ∀u ∃c ∃t': tau(t,u,c,t') & dst(t') & ~error(t,u,c)

    We use the direct substitution optimization (since t' <-> BDD(t,u,c)), thus:

        ∀u ∃c: (!error(t,u,c)  &  (dst(t)[t <- bdd_next_t(t,u,c)]))

    or for Moore machines:

        ∃c ∀u: (!error(t,u,c)  &  (dst(t)[t <- bdd_next_t(t,u,c)]))

    Note that we do not replace t variables in the error bdd.

    :return: BDD of the predecessor states
    **/

    // NOTE: I tried considering two special cases: error(t,u,c) and error(t),
    //       and move error(t) outside of quantification ∀u ∃c.
    //       It slowed down..
    // TODO: try again: on the driver example

    static vector<VecUint> orders;
    static bool did_grouping = false;

    if (!did_grouping && timer.sec_from_origin() > time_limit_sec/4) { // at 0.25*time_limit we fix the order
        do_grouping(cudd, orders);
        did_grouping = true;
    }

    dst = dst.VectorCompose(get_substitution());                                update_order_if(cudd, orders);

    if (is_moore) {
        BDD result = dst.And(~error);

        vector<BDD> uncontrollable = get_uncontrollable_vars_bdds();
        if (!uncontrollable.empty()) {
            BDD uncontrollable_cube = cudd.bddComputeCube(uncontrollable.data(),
                                                          NULL,
                                                          (int)uncontrollable.size());
            result = result.UnivAbstract(uncontrollable_cube);                  update_order_if(cudd, orders);
        }

        // ∃c ∀u  (...)
        vector<BDD> controllable = get_controllable_vars_bdds();
        BDD controllable_cube = cudd.bddComputeCube(controllable.data(),
                                                    NULL,
                                                    (int)controllable.size());
        result = result.ExistAbstract(controllable_cube);                       update_order_if(cudd, orders);
        return result;
    }

    // the case of Mealy machines
    vector<BDD> controllable = get_controllable_vars_bdds();
    BDD controllable_cube = cudd.bddComputeCube(controllable.data(),
                                                NULL,
                                                (int)controllable.size());
    BDD result = dst.AndAbstract(~error, controllable_cube);                   update_order_if(cudd, orders);

    vector<BDD> uncontrollable = get_uncontrollable_vars_bdds();
    if (!uncontrollable.empty()) {
        // ∀u ∃c (...)
        BDD uncontrollable_cube = cudd.bddComputeCube(uncontrollable.data(),
                                                      NULL,
                                                      (int)uncontrollable.size());
        result = result.UnivAbstract(uncontrollable_cube);                    update_order_if(cudd, orders);
    }
    return result;
}
/**
 * Build BDDs for the transition relation of the model.
 */
void BddTrAttachment::build()
{
  Options::Verbosity verbosity = _model.verbosity();
  if (verbosity > Options::Silent)
    cout << "Computing transition relation for model " << _model.name() << endl;
  BddAttachment const * bat = 
    (BddAttachment const *) _model.constAttachment(Key::BDD);
  assert(bat != 0);
  // The BDD attachment may not have BDDs because of a timeout.
  if (bat->hasBdds() == false) {
    _model.constRelease(bat);
    return;
  }
  if (hasBdds())
    return;
  ExprAttachment const * eat =
    (ExprAttachment *) _model.constAttachment(Key::EXPR);
  Expr::Manager::View *v = _model.newView();
  resetBddManager("bdd_tr_timeout");

  try {
    // Gather the conjuncts of the transition relation and initial condition.
    const vector<ID> sv = eat->stateVars();
    const vector<ID> iv = eat->inputs();
    const unordered_map<ID, int>& auxVar = bat->auxiliaryVars();
    int nvars = 2 * sv.size() + iv.size() + auxVar.size();
    if (verbosity > Options::Terse)
      cout << "number of variables = " << nvars << endl;
    BDD inputCube = bddManager().bddOne();
    for (vector<ID>::const_iterator i = iv.begin(); i != iv.end(); ++i) {
      BDD w = bat->bdd(*i);
      inputCube &= w;
    }
    BDD fwAbsCube = bddManager().bddOne();
    BDD bwAbsCube = bddManager().bddOne();
    vector<BDD> conjuncts;
    for (vector<ID>::const_iterator i = sv.begin(); i != sv.end(); ++i) {
      BDD x = bat->bdd(*i);
      _xvars.push_back(x);
      fwAbsCube &= x;
      ID nsv = v->prime(*i);
      BDD y = bat->bdd(nsv);
      _yvars.push_back(y);
      bwAbsCube &= y;
      ID nsf = eat->nextStateFnOf(*i);
      BDD f = bat->bdd(nsf);
      if (verbosity > Options::Informative)
        if (f.IsVar())
          cout << "Found a variable next-state function" << endl; 
      BDD t = y.Xnor(f);
      if (verbosity > Options::Verbose)
        reportBDD(stringOf(*v, nsv) + " <-> " + stringOf(*v, nsf),
                  t, nvars, verbosity, Options::Verbose);
      conjuncts.push_back(t);
    }

    // Process auxiliary variables.
    vector<BDD> conjAux;
    for (unordered_map<ID, int>::const_iterator it = auxVar.begin();
         it != auxVar.end(); ++it) {
      BDD f = bat->bdd(it->first);
      BDD v = bddManager().bddVar(it->second);
      BDD t = v.Xnor(f);
      conjAux.push_back(t);
      inputCube &= v;
    }
    conjuncts.insert(conjuncts.end(), conjAux.begin(), conjAux.end());
    // Build map from BDD variable indices to expression IDs.
    unordered_map<int, ID> index2id;
    for (unordered_map<ID, int>::const_iterator it = auxVar.begin();
         it != auxVar.end(); ++it) {
      index2id[it->second] = it->first;
    }

    // Add invariant constraints.
    const vector<ID> constr = eat->constraintFns();
    for (vector<ID>::const_iterator i = constr.begin(); 
         i != constr.end(); ++i) {
      BDD cn = bat->bdd(*i);
      composeAuxiliaryFunctions(bat, cn, index2id);
      _constr.push_back(cn);
      BDD cny = cn.ExistAbstract(inputCube);
      cny = cny.SwapVariables(_yvars, _xvars);
      reportBDD("Invariant constraint", cn, nvars, verbosity, Options::Terse);
      conjuncts.push_back(cn);
      conjuncts.push_back(cny);
    }

    unsigned int clusterLimit = 2500;
    if (_model.options().count("bdd_tr_cluster")) {
      clusterLimit = _model.options()["bdd_tr_cluster"].as<unsigned int>();
    }

    // Collect output functions applying invariant constraints and substituting
    // auxiliary variables.
    const vector<ID> outf = eat->outputs();
    for (vector<ID>::const_iterator i = outf.begin(); i != outf.end(); ++i) {
      BDD of = bat->bdd(eat->outputFnOf(*i));
      // Apply invariant constraints.
      for (vector<BDD>::iterator i = _constr.begin(); i != _constr.end(); ++i)
        of &= *i;
      composeAuxiliaryFunctions(bat, of, index2id);
      // Finally, remove primary inputs.
      if (_model.defaultMode() != Model::mFAIR) {
        of = of.ExistAbstract(inputCube);
      }
      _inv.push_back(of);
      reportBDD("Output function", of, _xvars.size(), verbosity,
                Options::Terse);
    }

    // Build the transition relation from the conjuncts.
    vector<BDD> sortedConjuncts = linearArrangement(conjuncts);
    assert(sortedConjuncts.size() == conjuncts.size());
    conjuncts.clear();
    vector<BDD> clusteredConjuncts =
      clusterConjuncts(sortedConjuncts, inputCube, clusterLimit, verbosity);
    assert(sortedConjuncts.size() == 0);
    inputCube = quantifyLocalInputs(clusteredConjuncts, inputCube,
                                    clusterLimit, verbosity);
    computeSchedule(clusteredConjuncts, inputCube);

    // Build initial condition.
    const vector<ID> ini = eat->initialConditions();
    _init = bddManager().bddOne();
    for (vector<ID>::const_iterator i = ini.begin(); i != ini.end(); ++i) {
      BDD ic = bat->bdd(*i);
      _init &= ic;
    }
    reportBDD("Initial condition", _init, _xvars.size(), verbosity,
              Options::Terse);
  } catch (Timeout& e) {
    bddManager().ClearErrorCode();
    bddManager().UnsetTimeLimit();
    bddManager().ResetStartTime();
    if (verbosity > Options::Silent)
      std::cout << e.what() << std::endl;
    _tr.clear();
    _xvars.clear();
    _yvars.clear();
    _inv.clear();
    _prequantx = bddManager().bddOne();
    _prequanty = bddManager().bddOne();
    _init = bddManager().bddZero();
  }
  delete v;
  _model.constRelease(eat);
  _model.constRelease(bat);

  bddManager().UpdateTimeLimit();

} // BddTrAttachment::build