/** * 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
/** * 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
/** * Eliminate auxiliary variables from output function. */ BDD BddTrAttachment::flattenOutput( const vector<BDD>& conjuncts, const BDD& wCube) { vector<BDD> schedule; for (vector<BDD>::size_type i = 0; i != conjuncts.size(); ++i) { schedule.push_back(bddManager().bddOne()); } // For each variable appearing in the conjuncts find the last // conjunct in which it appears. vector<int> lastSeen(bddManager().ReadSize(),-1); for (vector<BDD>::size_type i = 0; i != conjuncts.size(); ++i) { vector<unsigned int> support = conjuncts[i].SupportIndices(); for (vector<unsigned int>::const_iterator j = support.begin(); j != support.end(); ++j) { lastSeen[*j] = i; } } vector<unsigned int> wVars = wCube.SupportIndices(); #if 0 printVector("wVars", wVars); // Diagnostic printout. #endif for (vector<unsigned int>::size_type i = 0; i != wVars.size(); ++i) { unsigned int index = wVars[i]; int ls = lastSeen[index]; if (ls >= 0) { BDD var = bddManager().bddVar(index); schedule[ls] &= var; } } BDD ret = bddManager().bddOne(); for (vector<BDD>::size_type i = 0; i != conjuncts.size(); ++i) { ret = ret.AndAbstract(conjuncts[i], schedule[i]); } return ret; } // BddTrAttachment::flattenOutput
/** * Compose auxiliary functions recursively into a BDD. */ void BddTrAttachment::composeAuxiliaryFunctions( BddAttachment const * bat, BDD & f, unordered_map<int, ID> const & index2id) { vector<unsigned int> support = f.SupportIndices(); queue< vector<unsigned int> > q; q.push(support); while (!q.empty()) { vector<unsigned int> supp = q.front(); q.pop(); for (vector<unsigned int>::const_iterator j = supp.begin(); j != supp.end(); ++j) { unordered_map<int,ID>::const_iterator cit = index2id.find(*j); if (cit != index2id.end()) { BDD g = bat->bdd(cit->second); BDD a = bddManager().bddVar(*j); f = f.AndAbstract(a.Xnor(g),a); vector<unsigned int> addSupp = g.SupportIndices(); q.push(addSupp); } } } }
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; }
vector<BDD> BddTrAttachment::clusterConjuncts( vector<BDD>& conjuncts, const BDD& qcube, unsigned int limit, Options::Verbosity verbosity) const { vector<BDD> clusters; if (conjuncts.size() == 0) { clusters.push_back(bddManager().bddOne()); return clusters; } // Create records of occurrence of all variables in the conjuncts. // The variables that occur in no conjuncts end up with // earliest > latest. For the others, we know the first and last // conjunct in which they occur. unsigned int numvars = bddManager().ReadSize(); unsigned int nconjuncts = conjuncts.size(); vector<VarRec> occurrence; occurrence.reserve(numvars); for (unsigned int i = 0; i != numvars; ++i) { occurrence.push_back(VarRec(i,nconjuncts,-1)); } for (vector<BDD>::size_type i = 0; i != nconjuncts; ++i) { vector<unsigned int> support = conjuncts[i].SupportIndices(); for (vector<unsigned int>::const_iterator j = support.begin(); j != support.end(); ++j) { if (occurrence[*j].earliest() > (int) i) occurrence[*j].setEarliest((int) i); if (occurrence[*j].latest() < (int) i) occurrence[*j].setLatest((int) i); } } // Filter variables that are not candidates for quantification // and are not present in the conjuncts. vector<unsigned int> qvars = qcube.SupportIndices(); unordered_set<unsigned int> qset(qvars.begin(), qvars.end()); vector<VarRec> candidate; candidate.reserve(qvars.size()); for (vector<VarRec>::const_iterator i = occurrence.begin(); i != occurrence.end(); ++i) { if (qset.find(i->index()) != qset.end() && i->earliest() <= i->latest()) candidate.push_back(*i); } // Sort occurrence records according to latest occurrence // using earliest occurrence as tie breaker. stable_sort(candidate.begin(), candidate.end()); #if 0 // Diagnostic printout. for (vector<VarRec>::const_iterator i = candidate.begin(); i != candidate.end(); ++i) { cout << "Variable: " << i->index() << " (" << i->earliest() << "," << i->latest() << ")\n"; } #endif // We are now ready for clustering having collected the // information of which variables may be quantified when. // In the following, i points to the first conjunct in the cluster. // (Conjunct of highest index since we go backwards.) int i = conjuncts.size() - 1; BDD cluster = conjuncts[i]; conjuncts.pop_back(); // j points to the conjuncts that is being added to the cluster. int j = i - 1; // k points to the candidates for quantification vector<VarRec>::size_type k = 0; while (j >= 0) { reportBDD("conjunct", conjuncts[j], numvars, verbosity, Options::Informative); // Find variables that are local to cluster. A variable is local to // the current cluster if its lifespan is entirely contained between // i and j. BDD qcube = bddManager().bddOne(); while (k < candidate.size() && candidate[k].latest() > (int) i) k++; while (k < candidate.size() && candidate[k].earliest() >= (int) j) { qcube &= bddManager().bddVar(candidate[k].index()); k++; } BDD tmp = cluster.AndAbstract(conjuncts[j], qcube, limit); if (tmp && (unsigned int) tmp.nodeCount() <= 2*limit) { cluster = tmp; } else { reportBDD("Cluster", cluster, numvars, verbosity, Options::Informative); clusters.push_back(cluster); i = j; cluster = conjuncts[i]; } j--; conjuncts.pop_back(); } reportBDD("Cluster", cluster, numvars, verbosity, Options::Informative); clusters.push_back(cluster); return clusters; } // BddTrAttachment::clusterConjuncts