Example #1
0
  void techMap(Options::Verbosity verbosity, const ::AIGAttachment& aigat, unsigned k, unsigned b, unsigned refinements, ::std::vector<ID>& outputs, ::Expr::Manager::View& v, ::std::vector< ::std::vector<ID> >& cnf, ::std::vector<ID>& roots, double timeOut, bool add_roots)
  {
    // convert outputs into AIG references
    ::std::vector< ::Opt::NodeRef> aig_outputs;
    for(unsigned outi = 0; outi < outputs.size(); ++outi) {
      ::Opt::IDRefMap::const_iterator fit = aigat.id2ref.find(outputs[outi]);
      assert(fit != aigat.id2ref.end());
      aig_outputs.push_back(fit->second);
    }

    // make roots match the size of outputs
    roots.resize(aig_outputs.size());

    // a place for AIG CNF
    ::std::vector< ::std::vector< ::Opt::NodeRef> > nrcnf;

    // do CNF generation
    techMap(verbosity, aigat, k, b, refinements, aig_outputs, nrcnf, timeOut, add_roots);

    // convert AIG CNF to Expr CNF
    typedef ::std::vector< ::std::vector< ::Opt::NodeRef> > aigcnf;
    std::map< ::Opt::NodeIndex, ID> newvars;
    cnf.resize(0);
    unsigned clause = 0;
    for(aigcnf::iterator i = nrcnf.begin(); i != nrcnf.end(); ++i, ++clause) {
      cnf.resize(cnf.size()+1);
      for(::std::vector< ::Opt::NodeRef>::iterator j = i->begin(); j != i->end(); ++j) {
        ID lit;
        if(*j == 0) {
          // map to false
          lit =  v.bfalse();
        } else if(*j == 1) {
          // map to true
          lit = v.btrue();
        } else if(aigat.aig[ ::Opt::indexOf(*j)].isVar()) {
          // use existing inputs
          lit = aigat.ref2id.find(::Opt::refOf(::Opt::indexOf(*j), false))->second;
          if(::Opt::isNot(*j)) {
            // negate them if necessary
            lit = v.apply(::Expr::Not, lit);
          }
        } else {
          std::map< ::Opt::NodeIndex, ID>::iterator fj = newvars.find(::Opt::indexOf(*j));
          if(fj == newvars.end()) {
            // create new variable
            ::std::stringstream s;
            s << "tmv" << *j;
            lit = v.newVar(s.str());
            newvars[::Opt::indexOf(*j)] = lit;
          } else {
            // use existing var
            lit = fj->second;
          }
          if(::Opt::isNot(*j)) {
            lit = v.apply(::Expr::Not, lit);
          }
        }

        cnf[clause].push_back(lit);
      }
    }

    // fill in the roots vector
    unsigned j = 0;
    for(::std::vector< ::Opt::NodeRef>::iterator i = aig_outputs.begin(); i != aig_outputs.end(); ++i,++j) {
      if(*i == 0) {
        // map to false
        roots[j] = v.bfalse();
      } else if(*i == 1) {
        // map to true
        roots[j] = v.btrue();
      } else if(aigat.aig[ ::Opt::indexOf(*i)].isVar()) {
        // use existing input
        roots[j] = aigat.ref2id.find(::Opt::refOf(::Opt::indexOf(*i), false))->second;
        if(::Opt::isNot(*i)) {
          // negate as necessary
          roots[j] = v.apply(::Expr::Not, roots[j]);
        }
      } else {
        // use existing map
        std::map< ::Opt::NodeIndex, ID>::iterator fi = newvars.find(::Opt::indexOf(*i));
        // it should be found
        assert(fi != newvars.end());
        roots[j] = fi->second;
        if(::Opt::isNot(*i)) {
          // negate as necessary
          roots[j] = v.apply(::Expr::Not, roots[j]);
        }
      }
    }
  }
Example #2
0
/**
 * 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
void SequentialEquivalenceAction::exec() {
  TrivialEq teq;
  vector<EqualFn *> eqs;
  eqs.push_back(&teq);

  int rseed = model().options()["rand"].as<int>();
  if(rseed != -1)
    srand(rseed);

  ExprAttachment * const eat = (ExprAttachment *) model().constAttachment(Key::EXPR);

  Expr::Manager::View * ev = model().newView();

  FMap fmap;
  vector<ID> vars = eat->stateVars();
  for (vector<ID>::const_iterator it = vars.begin(); it != vars.end(); ++it)
    fmap.insert(FMap::value_type(*it, eat->nextStateFnOf(*it)));
 
  //uninitialized latches or those that get dropped out of ECs
  FMap singletonLatches = fmap; 

  // currently only works for AIGER 1.9 initial conditions
  Partition parts;
  set<ID> fpart, tpart;
  fpart.insert(ev->bfalse());
  tpart.insert(ev->btrue());
  vector<ID> init = eat->initialConditions();
  for (vector<ID>::const_iterator it = init.begin(); it != init.end(); ++it) {
    if (ev->op(*it) == Expr::Var) {
      tpart.insert(*it);
      singletonLatches.erase(*it);
    }
    else {
      fpart.insert(ev->apply(Expr::Not, *it));
      singletonLatches.erase(ev->apply(Expr::Not,*it));
    }
  }

  if (fpart.size() == 1 && tpart.size() == 1) {
    delete ev;
    return;
  }
  parts.push_back(fpart);
  parts.push_back(tpart);

  // Construct map of latches to fan-in latches.
  IDIDSetMap nsfSupport;
  for (vector<ID>::const_iterator it = vars.begin(); it != vars.end(); ++it) {
    set<ID> support;
    eat->supportStateVars(*ev, eat->nextStateFnOf(*it), support);
    nsfSupport.insert(IDIDSetMap::value_type(*it, support));
  }

  if (model().verbosity() > Options::Terse)
    cout << "SequentialEquivalenceAction starting" << endl;
  if (model().verbosity() > Options::Silent)
    cout << "SequentialEquivalence: Initial # latches = " << vars.size() << endl;

  //Refine classes
  if (model().verbosity() > Options::Informative)
    cout << "SequentialEquivalence: Simulation refinement" << endl;
  SimRefine simRefine(model(), ev, parts, fmap);
  sequentialSimulateRandom64(model(), 100, simRefine);

  CacheMap cache;
  ev->begin_local();
  for (vector<EqualFn *>::iterator eq = eqs.begin(); eq != eqs.end(); ++eq) {
    for (;;) {
      if (model().verbosity() > Options::Informative) {
        cout << " " << parts.size();
#if 0
        for (Partition::iterator it = parts.begin(); it != parts.end(); ++it)
          cout << " " << it->size();
#endif
        cout << endl;
      }
      FMap curr(fmap);
      iterate(ev, eat, parts, curr, nsfSupport, cache);
      if (!refine(ev, parts, curr, fmap, **eq)) {
        if (eq+1 == eqs.end()) {
          // globalize roots
          vector<ID> roots;
          for (FMap::const_iterator it = curr.begin(); it != curr.end(); ++it)
            roots.push_back(it->second);
          ev->global(roots);
          // make curr point to global roots
          unsigned int i = 0;
          for (FMap::iterator it = curr.begin(); it != curr.end(); ++it, ++i)
            it->second = roots[i];
          // save as fmap
          fmap = curr;
        }
        break;
      }
    }
  }
  ev->end_local();
  model().constRelease(eat);

  //Add latches that were dropped from ECs
  for (vector<ID>::const_iterator it = vars.begin(); it != vars.end(); ++it) {
    if (fmap.find(*it) == fmap.end())
      singletonLatches.insert(FMap::value_type(*it, eat->nextStateFnOf(*it)));
  }


  bool changed = false;
  for (Partition::const_iterator it = parts.begin(); it != parts.end(); ++it)
    if (it->size() > 1) {
      changed = true;
      break;
    }
  if (changed) {
    SeqAttachment * seqat = (SeqAttachment *) model().attachment(Key::SEQ);
    ExprAttachment * eat = (ExprAttachment *) model().attachment(Key::EXPR);

    FMap lmap;
    if(seqat->stateVars.empty()) {
      seqat->stateVars = eat->stateVars();
      seqat->nextStateFns = eat->nextStateFns();
    }
    eat->clearNextStateFns();
    map<ID, ID> latchToNsf;
    for (Partition::const_iterator it = parts.begin(); it != parts.end(); ++it) {
      // set next state function
      set<ID>::const_iterator rep = it->begin();
      if (*rep != ev->bfalse() && *rep != ev->btrue()) {
        FMap::const_iterator rit = fmap.find(*rep);
        latchToNsf.insert(map<ID, ID>::value_type(*rep, rit->second));
      }
      // build map of latch to representative latch
      set<ID>::const_iterator pit = rep;
      for (++pit; pit != it->end(); ++pit) {
        lmap.insert(FMap::value_type(*pit, *rep));
        seqat->optimized.insert(unordered_map<ID, ID>::value_type(*pit, *rep));
      }
    }
    for(FMap::const_iterator it = singletonLatches.begin();
        it != singletonLatches.end(); ++it) {
      ID nsf = Expr::varSub(*ev, lmap, it->second);
      latchToNsf.insert(map<ID, ID>::value_type(it->first, nsf));
    }
    for (map<ID, ID>::const_iterator it = latchToNsf.begin();
        it != latchToNsf.end(); ++it) {
      eat->setNextStateFn(it->first, it->second);
    }
    ev->keep(eat->nextStateFnOf(eat->stateVars()));

    if (model().verbosity() > Options::Silent)
      cout << "SequentialEquivalence: Final # latches = " << eat->stateVars().size() << endl;

    vector<ID> init(eat->initialConditions());
    if(seqat->initialConditions.empty())
      seqat->initialConditions = init;
    eat->clearInitialConditions();
    for (vector<ID>::iterator it = init.begin(); it != init.end(); ++it)
      if (Expr::varSub(*ev, lmap, *it) == *it)
        eat->addInitialCondition(*it);

    vector<ID> constraints(eat->constraints());
    vector<ID> constraintFns(eat->constraintFns());
    eat->clearConstraints();
    for (vector<ID>::size_type i = 0; i != constraintFns.size(); ++i) {
      //Changed by Zyad 11/08/2011
      //if (Expr::varSub(*ev, lmap, *it) == *it)
        //eat->addConstraint(*it);
      ID f = Expr::varSub(*ev, lmap, constraintFns[i]);
      eat->addConstraint(constraints[i], f);
    }
    ev->keep(eat->constraintFns());

    vector<ID> outputs(eat->outputs());
    vector<ID> outputFns(eat->outputFnOf(outputs));
    eat->clearOutputFns();
    Expr::varSub(*ev, lmap, outputFns);
    eat->setOutputFns(outputs, outputFns);
    ev->keep(outputFns);

    vector<ID> bad(eat->bad());
    vector<ID> badFns(eat->badFnOf(bad));
    eat->clearBadFns();
    Expr::varSub(*ev, lmap, badFns);
    eat->setBadFns(bad, badFns);
    ev->keep(badFns);

    vector<ID> fairness(eat->fairness());
    vector<ID> fairnessFns(eat->fairnessFnOf(fairness));
    eat->clearFairnessFns();
    Expr::varSub(*ev, lmap, fairnessFns);
    eat->setFairnessFns(fairness, fairnessFns);
    ev->keep(fairnessFns);

    vector<ID> justice(eat->justice());
    vector< vector<ID> > justiceS(eat->justiceSets());
    eat->clearJusticeSets();
    for (size_t i = 0; i < justiceS.size(); ++i) {
      Expr::varSub(*ev, lmap, justiceS[i]);
      eat->setJusticeSet(justice[i], justiceS[i]);
      ev->keep(justiceS[i]);
    }

    vector<ID> ctlProps(eat->ctlProperties());
    eat->clearCtlProperties();
    Expr::varSub(*ev, lmap, ctlProps);
    eat->addCtlProperties(ctlProps);

    model().release(eat);
    model().release(seqat);
  }
  else {
    if (model().verbosity() > Options::Silent)
      cout << "SequentialEquivalence: Final # latches = " << vars.size() << endl;
  }

  delete ev;
}
Example #4
0
void StuckAtAction::exec() {
  if (model().verbosity() > Options::Terse)
    cout << "StuckAtAction starting" << endl;

  ExprAttachment const * const eat = (ExprAttachment const *) model().constAttachment(Key::EXPR);
  AIGAttachment const * const aat = (AIGAttachment const *) model().constAttachment(Key::AIG);
  AIGTVSim tvsim(aat);
  Opt::RefIDMap const & idOfAigRef = aat->ref2id;

  Expr::Manager::View * v = model().newView();

  // assumes AIGER 1.9: every initial condition is specific to a latch
  vector<ID> init(eat->initialConditions());
  tvsim.reset(*v, init);

  bool changed = true;
  vector<TV> latchTVs(tvsim.latchBegin(), tvsim.latchEnd());
  int64_t start = Util::get_user_cpu_time();
  int64_t iter = 0;
  while (changed) {
    ++iter;
    tvsim.step();
    changed = false;
    const vector<TV> & nsValues = tvsim.getNSValues();
    for (unsigned i = 0; i < nsValues.size(); ++i) {
      if (nsValues[i] != latchTVs[i]) {
        changed = changed || (latchTVs[i] != TVX);
        latchTVs[i] = TVX;
      }
      else {
        latchTVs[i] = nsValues[i];
      }
    }
    copy(latchTVs.begin(), latchTVs.end(), tvsim.latchBegin());
  }
  model().constRelease(eat);
  if (model().verbosity() > Options::Terse)
    cout << "StuckAtAction: performed " << iter << " tvsim iterations in " << (Util::get_user_cpu_time() - start) / 1000000.0 << "s" << endl;

  Expr::IDMap sub;
  bool reduce = false;
  for (unsigned i = 0; i < latchTVs.size(); ++i)
    if (latchTVs[i] != TVX) {
      reduce = true;
      ID latchID = idOfAigRef.at(Opt::refOf(i + 1 + aat->aig.numInputs(), false));
      sub.insert(Expr::IDMap::value_type(latchID, latchTVs[i] == TVFalse ? 
                                                  v->bfalse() : v->btrue()));
    }
  if (reduce) {
    auto seat = model().attachment<SeqAttachment>(Key::SEQ);
    auto eat = model().attachment<ExprAttachment>(Key::EXPR);

    int cnt = 0;
    vector<ID> toSub;
    for (unsigned int i = 0; i < latchTVs.size(); ++i) {
      ID latchID = idOfAigRef.at(Opt::refOf(i + 1 + aat->aig.numInputs(), false));
      if (latchTVs[i] != TVX) {
        ++cnt;
        eat->setNextStateFn(latchID, latchTVs[i] == TVTrue ? v->btrue() : v->bfalse());
        seat->optimized.insert(unordered_map<ID, ID>::value_type(latchID,
            latchTVs[i] == TVTrue ? v->btrue() : v->bfalse()));
      }
      else {
        toSub.push_back(latchID);
      }
    }
    vector<ID> nnsfs = eat->nextStateFnOf(toSub);
    Expr::varSub(*v, sub, nnsfs);
    eat->setNextStateFns(toSub, nnsfs);
    v->keep(eat->nextStateFnOf(eat->stateVars()));

    if (model().verbosity() > Options::Silent)
      cout << "StuckAt: Found " << cnt << " stuck-at latches" << endl;

    vector<ID> constraints(eat->constraints());
    vector<ID> constraintFns(eat->constraintFns());
    eat->clearConstraints();
    for (vector<ID>::size_type i = 0; i != constraintFns.size(); ++i) {
      ID f = Expr::varSub(*v, sub, constraintFns[i]);
      eat->addConstraint(constraints[i], f);
    }
    v->keep(eat->constraintFns());

    vector<ID> outputs(eat->outputs());
    vector<ID> outputFns(eat->outputFnOf(outputs));
    eat->clearOutputFns();
    Expr::varSub(*v, sub, outputFns);
    eat->setOutputFns(outputs, outputFns);
    v->keep(outputFns);

    vector<ID> bad(eat->bad());
    vector<ID> badFns(eat->badFnOf(bad));
    eat->clearBadFns();
    Expr::varSub(*v, sub, badFns);
    eat->setBadFns(bad, badFns);
    v->keep(badFns);

    vector<ID> fairness(eat->fairness());
    vector<ID> fairnessFns(eat->fairnessFnOf(fairness));
    eat->clearFairnessFns();
    Expr::varSub(*v, sub, fairnessFns);
    eat->setFairnessFns(fairness, fairnessFns);
    v->keep(fairnessFns);

    vector<ID> justice(eat->justice());
    vector< vector<ID> > justiceS(eat->justiceSets());
    eat->clearJusticeSets();
    for (size_t i = 0; i < justiceS.size(); ++i) {
      Expr::varSub(*v, sub, justiceS[i]);
      eat->setJusticeSet(justice[i], justiceS[i]);
      v->keep(justiceS[i]);
    }

    model().release(eat);
    model().release(seat);
  }
  else if (model().verbosity() > Options::Silent)
    cout << "StuckAt: Found 0 stuck-at latches" << endl;

  delete v;
}