diff --git a/src/tests/safra.cc b/src/tests/safra.cc index 01d25e661..549513c0c 100644 --- a/src/tests/safra.cc +++ b/src/tests/safra.cc @@ -55,6 +55,7 @@ int main(int argc, char* argv[]) return 2; res = tgba_determinisation(aut->aut); } + res->merge_transitions(); spot::dotty_reachable(std::cout, res); } diff --git a/src/tests/safra.test b/src/tests/safra.test index 14cbbda06..2156270b6 100755 --- a/src/tests/safra.test +++ b/src/tests/safra.test @@ -22,7 +22,7 @@ . ./defs set -e -cat >input.hoa << EOF +cat >double_a.hoa << EOF HOA: v1 name: "F\"x > 1\"" States: 2 @@ -50,20 +50,21 @@ digraph G { 0 -> 1 [label="a"] 1 [label="1"] 1 -> 2 [label="a\n{0}"] - 1 -> 3 [label="b\n{3}"] + 1 -> 3 [label="!a & b\n{3}"] 2 [label="2"] 2 -> 1 [label="a"] - 2 -> 3 [label="b"] + 2 -> 3 [label="!a & b"] 3 [label="3"] - 3 -> 3 [label="b"] - 3 -> 0 [label="a"] + 3 -> 0 [label="a & !b"] + 3 -> 2 [label="a & b"] + 3 -> 3 [label="!a & b"] } EOF -run 0 ../safra --hoa input.hoa > out.dot +run 0 ../safra --hoa double_a.hoa > out.dot diff out.dot out.exp -cat >input.hoa << EOF +cat >double_b.hoa << EOF HOA: v1 name: "F\"x > 1\"" States: 2 @@ -90,13 +91,25 @@ digraph G { 0 [label="0"] 0 -> 1 [label="a"] 1 [label="1"] - 1 -> 1 [label="a"] - 1 -> 2 [label="b\n{0}"] + 1 -> 1 [label="a & !b"] + 1 -> 2 [label="a & b"] + 1 -> 3 [label="!a & b\n{0}"] 2 [label="2"] - 2 -> 2 [label="b\n{0}"] - 2 -> 0 [label="a"] + 2 -> 3 [label="!a & b\n{0}"] + 2 -> 4 [label="a & !b"] + 2 -> 5 [label="a & b"] + 3 [label="3"] + 3 -> 0 [label="a & !b"] + 3 -> 2 [label="a & b"] + 3 -> 3 [label="!a & b\n{0}"] + 4 [label="4"] + 4 -> 1 [label="a\n{0}"] + 4 -> 3 [label="!a & b\n{0}"] + 5 [label="5"] + 5 -> 1 [label="a\n{0}"] + 5 -> 3 [label="!a & b\n{0}"] } EOF -run 0 ../safra --hoa input.hoa > out.dot +run 0 ../safra --hoa double_b.hoa > out.dot diff out.dot out.exp diff --git a/src/twaalgos/safra.cc b/src/twaalgos/safra.cc index 6d9acb02f..7070d8980 100644 --- a/src/twaalgos/safra.cc +++ b/src/twaalgos/safra.cc @@ -18,6 +18,8 @@ // along with this program. If not, see . #include +#include +#include #include "safra.hh" #include "twaalgos/degen.hh" @@ -25,28 +27,37 @@ namespace spot { auto - safra_state::compute_succs(const const_twa_graph_ptr& aut) const -> succs_t + safra_state::compute_succs(const const_twa_graph_ptr& aut, + const std::vector& bddnums, + std::unordered_map, + bdd_hash>& deltas) const -> succs_t { succs_t res; // Given a bdd returns index of associated safra_state in res - std::map bdd2num; + std::map bdd2num; for (auto& node: nodes_) { for (auto& t: aut->out(node.first)) { - auto i = bdd2num.insert(std::make_pair(t.cond, res.size())); - unsigned idx; - if (!i.second) - idx = i.first->second; - else - { - // Each new node starts out with same number of nodes as src - idx = res.size(); - res.emplace_back(safra_state(nb_braces_.size()), t.cond); + auto p = deltas[t.cond]; + for (unsigned j = p.first; j < p.second; ++j) + { + auto i = bdd2num.insert(std::make_pair(bddnums[j], res.size())); + unsigned idx; + if (!i.second) + idx = i.first->second; + else + { + // Each new node starts out with same number of nodes as src + idx = res.size(); + res.emplace_back(safra_state(nb_braces_.size()), + bddnums[j]); + } + safra_state& ss = res[idx].first; + ss.update_succ(node.second, t.dst, t.acc); + assert(ss.nb_braces_.size() == ss.is_green_.size()); } - safra_state& ss = res[idx].first; - ss.update_succ(node.second, t.dst, t.acc); - assert(ss.nb_braces_.size() == ss.is_green_.size()); } } for (auto& s: res) @@ -231,11 +242,54 @@ namespace spot twa_graph_ptr tgba_determinisation(const const_twa_graph_ptr& a) { + // Degeneralize const_twa_graph_ptr aut; if (a->acc().is_generalized_buchi()) aut = spot::degeneralize_tba(a); else aut = a; + + + bdd allap = bddtrue; + { + typedef std::set sup_map; + sup_map sup; + // Record occurrences of all guards + for (auto& t: aut->transitions()) + sup.emplace(t.cond); + for (auto& i: sup) + allap &= bdd_support(i); + } + + // Preprocessing + // Used to convert atomic bdd to id + std::unordered_map bdd2num; + std::vector num2bdd; + // Nedded for compute succs + // Used to convert large bdd to indexes + std::unordered_map, bdd_hash> deltas; + std::vector bddnums; + for (auto& t: aut->transitions()) + { + auto it = deltas.find(t.cond); + if (it == deltas.end()) + { + bdd all = t.cond; + unsigned prev = bddnums.size(); + while (all != bddfalse) + { + bdd one = bdd_satoneset(all, allap, bddfalse); + all -= one; + auto p = bdd2num.emplace(one, num2bdd.size()); + if (p.second) + num2bdd.push_back(one); + bddnums.emplace_back(p.first->second); + } + deltas[t.cond] = std::make_pair(prev, bddnums.size()); + } + } + unsigned nc = bdd2num.size(); + auto res = make_twa_graph(aut->get_dict()); res->copy_ap_of(aut); res->prop_copy(aut, @@ -261,7 +315,7 @@ namespace spot safra_state curr = todo.front(); unsigned src_num = seen.find(curr)->second; todo.pop_front(); - succs_t succs = curr.compute_succs(aut); + succs_t succs = curr.compute_succs(aut, bddnums, deltas); for (auto s: succs) { auto i = seen.find(s.first); @@ -278,9 +332,10 @@ namespace spot seen.insert(std::make_pair(s.first, dst_num)); } if (s.first.color_ != -1U) - res->new_transition(src_num, dst_num, s.second, {s.first.color_}); + res->new_transition(src_num, dst_num, num2bdd[s.second], + {s.first.color_}); else - res->new_transition(src_num, dst_num, s.second); + res->new_transition(src_num, dst_num, num2bdd[s.second]); } } return res; diff --git a/src/twaalgos/safra.hh b/src/twaalgos/safra.hh index 747c3ab82..3ccf5912a 100644 --- a/src/twaalgos/safra.hh +++ b/src/twaalgos/safra.hh @@ -40,14 +40,18 @@ namespace spot class safra_state { public: - typedef std::vector> succs_t; + typedef std::vector> succs_t; bool operator<(const safra_state& other) const; // Print each sub-state with their associated braces of a safra state void print_debug(unsigned state_id); safra_state(unsigned state_number, bool init_state = false); // Given a certain transition_label, compute all the successors of that // label, and return that new node. - succs_t compute_succs(const const_twa_graph_ptr& aut) const; + succs_t compute_succs(const const_twa_graph_ptr& aut, + const std::vector& bddnums, + std::unordered_map, + bdd_hash>& deltas) const; // Used when creating the list of successors // A new intermediate node is created with src's braces and with dst as id // A merge is done if dst already existed in *this