/** * 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
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