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]); } } } }
/** * 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; }
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; }