/** * Cluster conjuncts to produce a partitioned transition relation. * * Conjuncts larger than limit are rejected (unless they are * singletons). */ vector<BDD> BddTrAttachment::clusterConjunctsOld( vector<BDD>& conjuncts, unsigned int limit, Options::Verbosity verbosity, int nvars) const { vector<BDD> clusters; if (conjuncts.size() == 0) { clusters.push_back(bddManager().bddOne()); return clusters; } vector<BDD>::const_reverse_iterator it = conjuncts.rbegin(); BDD cluster = *it++; conjuncts.pop_back(); while (it != conjuncts.rend()) { reportBDD("conjunct", *it, nvars, verbosity, Options::Informative); BDD tmp = cluster.And(*it,limit); if (tmp && (unsigned int) tmp.nodeCount() <= 2*limit) { cluster = tmp; } else { reportBDD("Cluster", cluster, nvars, verbosity, Options::Informative); clusters.push_back(cluster); cluster = *it; } ++it; conjuncts.pop_back(); } reportBDD("Cluster", cluster, nvars, verbosity, Options::Informative); clusters.push_back(cluster); return clusters; } // BddTrAttachment::clusterConjunctsOld
/** * Quantify local primary input and auxiliary variables. */ BDD BddTrAttachment::quantifyLocalInputs( vector<BDD>& conjuncts, const BDD& qcube, unsigned int limit, Options::Verbosity verbosity) const { // A -1 means "not yet seen." // A -2 means "seen in more than one conjunct." vector<int> whereSeen(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) { if (whereSeen[*j] == -1) whereSeen[*j] = i; else whereSeen[*j] = -2; } } // Attempt quantification of variables seen exactly once, but // back off if this blows up the conjunct. vector<unsigned int> qvars = qcube.SupportIndices(); BDD ret = bddManager().bddOne(); for (vector<unsigned int>::size_type i = 0; i != qvars.size(); ++i) { unsigned int index = qvars[i]; BDD bvar = bddManager().bddVar(qvars[i]); int ws = whereSeen[index]; if (ws >= 0) { int currentLimit = conjuncts[ws].nodeCount(); BDD tmp = conjuncts[ws].ExistAbstract(bvar, currentLimit); if (tmp && tmp.nodeCount() <= currentLimit) { conjuncts[ws] = tmp; #if 0 cout << "Eliminated local variable " << index << " from conjunct " << ws << endl; #endif } else { #if 0 cout << "Failed to eliminate local variable " << index << " from conjunct " << ws << endl; #endif ret &= bvar; } } else { ret &= bvar; } } assert(qcube <= ret); if (verbosity > Options::Terse) cout << "Number of clusters/nodes = " << conjuncts.size() << "/" << bddManager().SharingSize(conjuncts) << endl; return ret; } // BddTrAttachment::quantifyLocalInputs
/** * 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
void Synth::model_to_aiger(const BDD &c_signal, const BDD &func) { /// Update AIGER spec with a definition of `c_signal` uint c_lit = aiger_by_cudd[c_signal.NodeReadIndex()]; string output_name = string(aiger_is_input(aiger_spec, c_lit)->name); // save the name before it is freed uint func_as_aiger_lit = walk(func.getNode()); aiger_redefine_input_as_and(aiger_spec, c_lit, func_as_aiger_lit, func_as_aiger_lit); if (print_full_model) aiger_add_output(aiger_spec, c_lit, output_name.c_str()); }
void Jeu::conjugaison() /// boucle principale du jeu { srand(SDL_GetTicks()); m_in->activerSaisie(); BDD * dico = new BDD("ressources/datas/database.db"); for(int i = 0 ; i < 20 ; i++) { std::vector<std::vector<std::string> > dataC; int hazard = rand()%(10-1) + 1; string temp = "SELECT nom,pluralite,personne FROM pronom WHERE id = " + toString(hazard); dataC = dico->request((char*)temp.c_str()); data2[i*5+0] = dataC[0][0]; data2[i*5+2] = dataC[0][1]; data2[i*5+3] = dataC[0][2]; hazard = rand()%(4-1) + 1; temp = "SELECT infinitif FROM verbe WHERE id = " + toString(hazard); dataC = dico->request((char*)temp.c_str()); data2[i*5+4] = dataC[0][0]; temp = "SELECT " + data2[i*5+3] + "_" + data2[i*5+2] + " FROM indicatif_present WHERE id = " + toString(hazard); dataC = dico->request((char*)temp.c_str()); data2[i*5+1] = dataC[0][0]; cout << data2[i*5+0] << " " << data2[i*5+1] << " " << data2[i*5+2] << " " << data2[i*5+3] << " " << data2[i*5+4] << endl; } delete dico; while(!m_in->get_touche(SDLK_ESCAPE) && !m_in->get_exit()) { /// met à jour les evenements d'entree m_in->update(); /// régule le fps timer(); /// resize taille écran resizeScreen(); /// mécanique du jeu mecanique2(); /// affichage du jeu affichage2(); } }
/** * 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
/** Reads a file containing a binary relation. One pair per line. */ BDD read_binrel(const char* fname) { unordered_map<int,int> normalize; BDD br = Cudd::zero(); string line; ifstream input(fname); if (input.is_open()) { while (input.good()) { getline(input,line); stringstream ss(line); int first, second; ss >> first; ss >> second; encode(normalize,first); encode(normalize, second); br |= BDD::create(make_tuple(first,second)); //tuples.push_back(make_pair(first,second)); } input.close(); cout << "Pairs in the relation: " << br.minterms(2) << endl; //Cudd::stats(); } else {
/** * 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); } } } }
int execQueens(int n, std::string com) { // clocks for performance analysis clock_t start, end; double elapsed; start = clock(); std::ostringstream namefich; BDD* bdd = new BDD(); bdd->setNbVar(n*n); int pos = 0; std::ostringstream oss; namefich << "test" << pos << ".txt"; std::string namefichstr = namefich.str(); std::ofstream fichier(namefichstr, std::ios::out | std::ios::trunc); namefich.str(""); namefich.clear(); BDD* bdd1 = new BDD(bdd->getNbVar(), bdd->getVectorNode(), bdd->getVectNode(), bdd->getNodeFalse(), bdd->getNodeTrue(), bdd->getVarorder(), bdd->getOrdervar(), bdd->getMaxIndice(), bdd->getOpmap()); BDD* bddtemp1; for (int i=0; i < n; i++) { bddtemp1 = new BDD(bdd1->getNbVar(), bdd1->getVectorNode(), bdd1->getVectNode(), bdd1->getNodeFalse(), bdd1->getNodeTrue(), bdd1->getVarorder(), bdd1->getOrdervar(), bdd1->getMaxIndice(), bdd1->getOpmap()); for (int j=0; j < n; j++) { oss << "( c"<<i<<j<<" & "; bool first = true; for (int h = 0; h < n; h++) { if (h != j) { if (!first) oss << " & "; oss << "!c"<<i<<h; first = false; } } oss << " )"; bddtemp1 = bddtemp1->orfonc(bddtemp1, oss.str()); oss.str(""); oss.clear(); } bdd1 = bdd1->andfonc(bdd1, bddtemp1); bdd1 = bdd1->transferinfo(bddtemp1, bdd1); oss.str(""); oss.clear(); } std::cout << "fin premier bdd" << std::endl; /*oss << " & ";*/ BDD* bdd2 = new BDD(bdd1->getNbVar(), bdd1->getVectorNode(), bdd1->getVectNode(), bdd1->getNodeFalse(), bdd1->getNodeTrue(), bdd1->getVarorder(), bdd1->getOrdervar(), bdd1->getMaxIndice(), bdd1->getOpmap()); BDD* bddtemp2; for (int i=0; i < n; i++) { bddtemp2 = new BDD(bdd2->getNbVar(), bdd2->getVectorNode(), bdd2->getVectNode(), bdd2->getNodeFalse(), bdd2->getNodeTrue(), bdd2->getVarorder(), bdd2->getOrdervar(), bdd2->getMaxIndice(), bdd2->getOpmap()); for (int j=0; j < n; j++) { oss << "( c"<<j<<i<<" & "; bool first = true; for (int h = 0; h < n; h++) { if (h != j) { if (!first) oss << " & "; oss << "!c"<<h<<i; first = false; } } oss << " )"; bddtemp2 = bddtemp2->orfonc(bddtemp2, oss.str()); oss.str(""); oss.clear(); } bdd2 = bdd2->andfonc(bdd2, bddtemp2); bdd2 = bdd2->transferinfo(bddtemp2, bdd2); oss.str(""); oss.clear(); } std::cout << "fin second bdd" << std::endl; /*oss << " & ";*/ BDD* bdd3 = new BDD(bdd2->getNbVar(), bdd2->getVectorNode(), bdd2->getVectNode(), bdd2->getNodeFalse(), bdd2->getNodeTrue(), bdd2->getVarorder(), bdd2->getOrdervar(), bdd2->getMaxIndice(), bdd2->getOpmap()); BDD* bddtemp3; for (int i = 0; i < n; i++) { bddtemp3 = new BDD(bdd3->getNbVar(), bdd3->getVectorNode(), bdd3->getVectNode(), bdd3->getNodeFalse(), bdd3->getNodeTrue(), bdd3->getVarorder(), bdd3->getOrdervar(), bdd3->getMaxIndice(), bdd3->getOpmap()); for (int j=0; j < n; j++) { oss << "( c"<<i<<j; std::ostringstream osstemp; bool first = true; for (int h = 0; h < n; h++) { int val = j+h-i; if (h != i && val>=0 && val<n) { if (first) osstemp <<" & ( "; if (!first) osstemp << " & "; osstemp << "!c"<<h<<val; first = false; } } std::string temp = osstemp.str(); if (temp != "") oss << temp << " ) )"; else oss << " )"; bddtemp3 = bddtemp3->orfonc(bddtemp3, oss.str()); oss.str(""); oss.clear(); } bdd3 = bdd3->andfonc(bdd3, bddtemp3); bdd3 = bdd3->transferinfo(bddtemp3, bdd3); oss.str(""); oss.clear(); } std::cout << "fin troisieme bdd" << std::endl; /*oss << " & ";*/ BDD* bdd4 = new BDD(bdd3->getNbVar(), bdd3->getVectorNode(), bdd3->getVectNode(), bdd3->getNodeFalse(), bdd3->getNodeTrue(), bdd3->getVarorder(), bdd3->getOrdervar(), bdd3->getMaxIndice(), bdd3->getOpmap()); BDD* bddtemp4; for (int i = 0; i < n; i++) { bddtemp4 = new BDD(bdd4->getNbVar(), bdd4->getVectorNode(), bdd4->getVectNode(), bdd4->getNodeFalse(), bdd4->getNodeTrue(), bdd4->getVarorder(), bdd4->getOrdervar(), bdd4->getMaxIndice(), bdd4->getOpmap()); for (int j=0; j < n; j++) { oss << "( c"<<i<<j; std::ostringstream osstemp; bool first = true; for (int h = 0; h < n; h++) { int val = j+i-h; if (h != i && val>=0 && val<n) { if (first) osstemp <<" & ( "; if (!first) osstemp << " & "; osstemp << "!c"<<h<<val; first = false; } } std::string temp = osstemp.str(); if (temp != "") oss << temp << " ) )"; else oss << " )"; bddtemp4 = bddtemp4->orfonc(bddtemp4, oss.str()); oss.str(""); oss.clear(); } bdd4 = bdd4->andfonc(bdd4, bddtemp4); bdd4 = bdd4->transferinfo(bddtemp4, bdd4); oss.str(""); oss.clear(); } std::cout << "fin quatrieme bdd" << std::endl; bdd = bdd->andfonc(bdd, bdd1); std::cout << "fin apply1" << std::endl; bdd = bdd->andfonc(bdd, bdd2); std::cout << "fin apply2" << std::endl; bdd = bdd->andfonc(bdd, bdd3); std::cout << "fin apply3" << std::endl; bdd = bdd->andfonc(bdd, bdd4); std::cout << "fin apply4" << std::endl; if (com == "satcount") std::cout << "Nombre de solution satisfaisante pour bdd: " << bdd->satcount() << std::endl; else if (com == "anysat") std::cout << "Une solution: " << bdd->anysat() << std::endl; else if (com == "allsat") { std::cout << "Toutes les solutions:" << std::endl; bdd->allsat(); } // performance analysis end = clock(); elapsed = ((double)end - start) / CLOCKS_PER_SEC; std::cout << "Execution time : " << elapsed << std::endl; return 0; }
hmap<uint,BDD> Synth::extract_output_funcs() { /** The result vector respects the order of the controllable variables **/ L_INF("extract_output_funcs.."); cudd.FreeTree(); // ordering that worked for win region computation might not work here hmap<uint,BDD> model_by_cuddidx; vector<BDD> controls = get_controllable_vars_bdds(); while (!controls.empty()) { BDD c = controls.back(); controls.pop_back(); aiger_symbol *aiger_input = aiger_is_input(aiger_spec, aiger_by_cudd[c.NodeReadIndex()]); L_INF("getting output function for " << aiger_input->name); BDD c_arena; if (controls.size() > 0) { BDD cube = cudd.bddComputeCube(controls.data(), NULL, (int)controls.size()); c_arena = non_det_strategy.ExistAbstract(cube); } else { //no other signals left c_arena = non_det_strategy; } // Now we have: c_arena(t,u,c) = ∃c_others: nondet(t,u,c) // (i.e., c_arena talks about this particular c, about t and u) BDD c_can_be_true = c_arena.Cofactor(c); BDD c_can_be_false = c_arena.Cofactor(~c); BDD c_must_be_true = ~c_can_be_false & c_can_be_true; BDD c_must_be_false = c_can_be_false & ~c_can_be_true; // Note that we cannot use `c_must_be_true = ~c_can_be_false`, // since the negation can cause including tuples (t,i,o) that violate non_det_strategy. auto support_indices = cudd.SupportIndices(vector<BDD>({c_must_be_false, c_must_be_true})); for (auto const var_cudd_idx : support_indices) { auto v = cudd.ReadVars(var_cudd_idx); auto new_c_must_be_false = c_must_be_false.ExistAbstract(v); auto new_c_must_be_true = c_must_be_true.ExistAbstract(v); if ((new_c_must_be_false & new_c_must_be_true) == cudd.bddZero()) { c_must_be_false = new_c_must_be_false; c_must_be_true = new_c_must_be_true; } } // We use 'restrict' operation, but we could also just do: // c_model = care_set -> must_be_true // but this is (presumably) less efficient (in time? in size?). // (intuitively, because we always set c_model to 1 if !care_set, but we could set it to 0) // // The result of restrict operation satisfies: // on c_care_set: c_must_be_true <-> must_be_true.Restrict(c_care_set) BDD c_model = c_must_be_true.Restrict(c_must_be_true | c_must_be_false); model_by_cuddidx[c.NodeReadIndex()] = c_model; //killing node refs c_must_be_false = c_must_be_true = c_can_be_false = c_can_be_true = c_arena = cudd.bddZero(); //TODO: ak: strange -- the python version for the example amba_02_9n produces a smaller circuit (~5-10 times)! non_det_strategy = non_det_strategy.Compose(c_model, c.NodeReadIndex()); //non_det_strategy = non_det_strategy & ((c & c_model) | (~c & ~c_model)); } return model_by_cuddidx; }
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; }
/** * Compute the quantification schedule for the primary inputs and the * auxiliary variables. */ void BddTrAttachment::computeSchedule( const vector<BDD>& conjuncts, const BDD& wCube) { vector<BDD> fwSchedule, bwSchedule; for (vector<BDD>::size_type i = 0; i != conjuncts.size(); ++i) { fwSchedule.push_back(bddManager().bddOne()); bwSchedule.push_back(bddManager().bddOne()); } _prequantx = bddManager().bddOne(); _prequanty = 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); fwSchedule[ls] &= var; bwSchedule[ls] &= var; } } for (vector<BDD>::size_type i = 0; i != _xvars.size(); ++i) { unsigned int index = _xvars[i].NodeReadIndex(); int ls = lastSeen[index]; if (ls >= 0) { fwSchedule[ls] &= _xvars[i]; } else { _prequantx &= _xvars[i]; } } for (vector<BDD>::size_type i = 0; i != _yvars.size(); ++i) { unsigned int index = _yvars[i].NodeReadIndex(); int ls = lastSeen[index]; if (ls >= 0) { bwSchedule[ls] &= _yvars[i]; } else { _prequanty &= _yvars[i]; } } for (vector<BDD>::size_type i = 0; i != conjuncts.size(); ++i) { _tr.push_back(RelPart(conjuncts[i], fwSchedule[i], bwSchedule[i])); } } // BddTrAttachment::computeSchedule
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
/** * 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
unsigned approximate_additional_lines( const std::string& filename, properties::ptr settings, properties::ptr statistics ) { /* Timer */ properties_timer t( statistics ); /* Number of inputs and outputs */ unsigned n = 0u; unsigned m = 0u; /* Parse PLA */ std::ifstream is; is.open(filename.c_str()); std::string line; /* For the BDD */ Cudd mgr(0, 0); BDD u = mgr.bddZero(); std::vector<BDD> variables; /* MU hash table */ std::map<std::string, mpz_class> mu; while(std::getline(is, line)) { using boost::algorithm::starts_with; using boost::algorithm::trim; trim(line); if (line.size() == 0u) continue; if (starts_with(line, ".i ")) { n = parse_number_from_pla_command(line); variables.resize(n); boost::generate(variables, [&mgr](){ return mgr.bddVar(); }); } else if (starts_with(line, ".o ")) { m = parse_number_from_pla_command(line); } else if (starts_with(line, "#")) { /* ignore comments */ } else if (!starts_with(line, ".")) { using boost::algorithm::split; using boost::algorithm::is_any_of; using boost::algorithm::token_compress_on; /* Split cubes */ std::vector<std::string> split_result; split(split_result, line, is_any_of("\t "), token_compress_on); /* Assign cubes to local variables */ const std::string& incube = split_result.at(0u); std::string outcube = split_result.at(1u); boost::replace_all( outcube, "-", "0" ); /* Calculate number of patterns */ BDD cube = create_bdd_from_incube(mgr, incube, variables); mpz_class patterns(cube.CountMinterm(n)); /* Update entry in mu */ if (mu.find(outcube) == mu.end()) { mu[outcube] = patterns; } else { mu[outcube] += patterns; } /* Update used cubes BDD */ u |= cube; } } /* Cubes that map to zero */ std::string zerocube = std::string(m, '0'); mpz_class zeromu = pow2(n) - mpz_class(u.CountMinterm(n)); /* It could be that there has been a mapping to 0 in the PLA, just in case */ if (mu.find(zerocube) == mu.end()) { mu[zerocube] = zeromu; } else { mu[zerocube] += zeromu; } is.close(); /* Maximum MU */ using boost::adaptors::map_values; for ( auto v : mu ) { #ifdef DEBUG std::cout << v.first << " has " << v.second << std::endl; #endif } mpz_class maxmu = *boost::max_element(mu | map_values); /* Statistics */ if ( statistics ) { statistics->set( "num_inputs", n ); statistics->set( "num_outputs", m ); } return calculate_required_lines(n, m, maxmu) - n; }