diff --git a/spot/twa/acc.cc b/spot/twa/acc.cc index 7891e3b3b..80e581a50 100644 --- a/spot/twa/acc.cc +++ b/spot/twa/acc.cc @@ -1060,6 +1060,60 @@ namespace spot return res; } + namespace + { + bool + has_parity_prefix_aux(acc_cond original, + acc_cond &new_cond, + std::vector &colors, + std::vector elements, + acc_cond::acc_op op) + { + acc_cond::mark_t empty_m = {}; + if (elements.size() > 2) + { + new_cond = original; + return false; + } + if (elements.size() == 2) + { + unsigned pos = elements[1].back().sub.op == op && + elements[1][0].mark.count() == 1; + if (!(elements[0].back().sub.op == op || pos)) + { + new_cond = original; + return false; + } + if ((elements[1 - pos].used_sets() & elements[pos][0].mark) != empty_m) + { + new_cond = original; + return false; + } + if (elements[pos][0].mark.count() != 1) + { + return false; + } + colors.push_back(elements[pos][0].mark.min_set() - 1); + elements[1 - pos].has_parity_prefix(new_cond, colors); + return true; + } + return false; + } + } + + bool + acc_cond::acc_code::has_parity_prefix(acc_cond &new_cond, + std::vector &colors) const + { + auto disj = top_disjuncts(); + if (!(has_parity_prefix_aux((*this), new_cond, colors, + disj, acc_cond::acc_op::Inf) || + has_parity_prefix_aux((*this), new_cond, colors, + top_conjuncts(), acc_cond::acc_op::Fin))) + new_cond = acc_cond((*this)); + return disj.size() == 2; + } + bool acc_cond::has_parity_prefix(acc_cond& new_cond, std::vector& colors) const @@ -1082,18 +1136,6 @@ namespace spot return result; } - std::vector - acc_cond::colors_inf_conj(unsigned min_nb_colors) - { - return code_.colors_inf_conj(min_nb_colors); - } - - std::vector - acc_cond::colors_fin_disj(unsigned min_nb_colors) - { - return code_.colors_fin_disj(min_nb_colors); - } - bool acc_cond::is_parity(bool& max, bool& odd, bool equiv) const { unsigned sets = num_; @@ -2520,6 +2562,124 @@ namespace spot return -1; } + namespace + { + bool + find_unit_clause(acc_cond::acc_code code, bool& conj, bool& fin, + acc_cond::mark_t& res) + { + res = {}; + acc_cond::mark_t possibles = ~code.used_once_sets(); + bool found_one = false; + conj = false; + fin = false; + if (code.empty() || code.is_f()) + return false; + const acc_cond::acc_word* pos = &code.back(); + conj = (pos->sub.op == acc_cond::acc_op::And); + do + { + switch (pos->sub.op) + { + case acc_cond::acc_op::And: + if (!conj) + pos -= pos->sub.size + 1; + else + --pos; + break; + case acc_cond::acc_op::Or: + if (conj) + pos -= pos->sub.size + 1; + else + --pos; + break; + case acc_cond::acc_op::Inf: + case acc_cond::acc_op::InfNeg: + case acc_cond::acc_op::FinNeg: + if (!fin) + { + auto m = pos[-1].mark & possibles; + if (m.count() == 1 || conj) + { + found_one = true; + res |= m; + } + } + pos -= 2; + break; + case acc_cond::acc_op::Fin: + if (!found_one || fin) + { + auto m = pos[-1].mark & possibles; + if (m.count() == 1 || !conj) + { + found_one = true; + fin = true; + res |= m; + } + } + pos -= 2; + break; + } + } + while (pos >= &code.front()); + return res != acc_cond::mark_t {}; + } + } + + acc_cond::acc_code + acc_cond::acc_code::unit_propagation() + { + bool fin, conj; + acc_cond::mark_t mark; + acc_code result = (*this); + acc_code code; + if (result.size() > 1 && + (result.back().sub.op == acc_cond::acc_op::And + || result.back().sub.op == acc_cond::acc_op::Or)) + { + while (find_unit_clause(result, conj, fin, mark)) + { + acc_code init_code; + if (fin) + init_code = acc_code::fin(mark); + else + init_code = acc_code::inf(mark); + if (conj) + result = init_code & result.remove(mark, fin == conj); + else + result = init_code | result.remove(mark, fin == conj); + } + + auto pos = &result.back(); + auto fo = pos->sub.op; + bool is_and = (fo == acc_cond::acc_op::And); + std::vector propagated; + acc_cond::acc_code res; + if (is_and) + res = acc_cond::acc_code::t(); + else + res = acc_cond::acc_code::f(); + if (is_and || fo == acc_cond::acc_op::Or) + { + --pos; + while (pos >= &result.front()) + { + propagated.push_back(acc_code(pos).unit_propagation()); + pos -= pos->sub.size + 1; + } + result = std::accumulate(propagated.rbegin(), propagated.rend(), res, + [&](acc_cond::acc_code c1, acc_cond::acc_code c2) + { + if (is_and) + return c1 & c2; + return c1 | c2; + }); + } + } + return result; + } + acc_cond::mark_t acc_cond::acc_code::fin_unit() const { mark_t res = {}; diff --git a/spot/twa/acc.hh b/spot/twa/acc.hh index 6c17d073f..56390c227 100644 --- a/spot/twa/acc.hh +++ b/spot/twa/acc.hh @@ -70,12 +70,6 @@ namespace spot #endif public: - std::vector - colors_inf_conj(unsigned min_nb_colors); - - std::vector - colors_fin_disj(unsigned min_nb_colors); - /// \brief An acceptance mark /// /// This type is used to represent a set of acceptance sets. It @@ -469,250 +463,12 @@ namespace spot /// provided methods instead. struct SPOT_API acc_code: public std::vector { - private: - bool - get_alone_mark(bool& fin, acc_cond::mark_t& mark, bool& conj, - acc_code& code) - { - auto elements = top_conjuncts(); - conj = (elements.size() > 1); - if (!conj) - { - elements = top_disjuncts(); - if (elements.size() < 2) - return false; - } - - for (auto c : elements) - { - auto op = c.back().sub.op; - fin = (op == acc_cond::acc_op::Fin); - if ((fin || op == acc_cond::acc_op::Inf) && c[0].mark.count() == 1 - && (used_once_sets() & c[0].mark) == acc_cond::mark_t {}) - { - mark = c[0].mark; - code = c; - return true; - } - } - return false; - } - - public: acc_code - propagate_fin_inf() - { - bool fin = false, conj; - acc_cond::mark_t mark; - acc_code result = (*this); - acc_code code; - while (result.get_alone_mark(fin, mark, conj, code)) - { - auto elements = result.top_disjuncts(); - if (elements.size() < 2) - elements = result.top_conjuncts(); - acc_code init_code; - if (conj) - init_code = acc_code::t(); - else - init_code = acc_code::f(); - bool keeped_code = false; - result = std::accumulate(elements.rbegin(), elements.rend(), - init_code, - [&](acc_code a, acc_code b) - { - if (b != code || keeped_code) - b = b.remove(mark, fin == conj); - if (b == code) - keeped_code = true; - if (conj) - return a & b; - else - return a | b; - }); - } - std::vector elements = result.top_disjuncts(); - if (elements.size() < 2) - elements = result.top_conjuncts(); - if (elements.size() > 1) - { - acc_code init_code; - if (conj) - init_code = acc_code::t(); - else - init_code = acc_code::f(); - result = std::accumulate(elements.rbegin(), elements.rend(), - init_code, - [&](acc_code a, acc_code b) - { - if (conj) - return a & b.propagate_fin_inf(); - else - return a | b.propagate_fin_inf(); - }); - } - return result; - } - - std::vector - colors_inf_conj(unsigned min_nb_colors = 2) - { - auto result = std::vector(); - auto conj = top_conjuncts(); - if (conj.size() != 1) - { - std::sort(conj.begin(), conj.end(), - [](acc_code c1, acc_code c2) - { - (void)c2; - return c1.back().sub.op == acc_cond::acc_op::Inf; - }); - unsigned i = 0; - while (i < conj.size()) - { - acc_cond::acc_code elem = conj[i]; - if (elem.back().sub.op == acc_cond::acc_op::Inf) - { - if (elem[0].mark.count() == 1) - result.insert(result.end(), elem[0].mark.min_set() - 1); - } else - break; - ++i; - } - if (result.size() >= min_nb_colors) - return result; - while (i < conj.size()) - { - result = conj[i].colors_inf_conj(); - if (result.size() >= min_nb_colors) - return result; - result.clear(); - ++i; - } - } - else - { - auto disj = top_disjuncts(); - if (disj.size() > 1) - { - for (auto elem : disj) - { - result = elem.colors_inf_conj(); - if (result.size() >= min_nb_colors) - return result; - result.clear(); - } - } - else - return {}; - } - return result; - } - - std::vector - colors_fin_disj(unsigned min_nb_colors = 2) - { - auto result = std::vector(); - auto disj = top_disjuncts(); - if (disj.size() != 1) - { - std::sort(disj.begin(), disj.end(), - [](acc_code c1, acc_code c2) - { - (void) c2; - return c1.back().sub.op == acc_cond::acc_op::Fin; - }); - unsigned i = 0; - while (i < disj.size()) - { - acc_cond::acc_code elem = disj[i]; - if (elem.back().sub.op == acc_cond::acc_op::Fin) - { - if (elem[0].mark.count() == 1) - result.insert(result.end(), elem[0].mark.min_set() - 1); - } else - break; - ++i; - } - if (result.size() >= min_nb_colors) - return result; - while (i < disj.size()) - { - result = disj[i].colors_fin_disj(); - if (result.size() >= min_nb_colors) - return result; - result.clear(); - ++i; - } - } - else - { - auto disj = top_conjuncts(); - if (disj.size() > 1) - { - for (auto elem : disj) - { - result = elem.colors_fin_disj(); - if (result.size() >= min_nb_colors) - return result; - result.clear(); - } - } - else - return {}; - } - return result; - } + unit_propagation(); bool - has_parity_prefix_aux(spot::acc_cond& new_cond, - std::vector& colors, std::vector elements, - acc_cond::acc_op op) const - { - mark_t empty_m = { }; - if (elements.size() > 2) - { - new_cond = (*this); - return false; - } - if (elements.size() == 2) - { - unsigned pos = elements[1].back().sub.op == op - && elements[1][0].mark.count() == 1; - if (!(elements[0].back().sub.op == op || pos)) - { - new_cond = (*this); - return false; - } - if ((elements[1 - pos].used_sets() & elements[pos][0].mark) - != empty_m) - { - new_cond = (*this); - return false; - } - if (elements[pos][0].mark.count() != 1) - { - return false; - } - colors.push_back(elements[pos][0].mark.min_set() - 1); - elements[1 - pos].has_parity_prefix(new_cond, colors); - return true; - } - return false; - } - - bool has_parity_prefix(spot::acc_cond& new_cond, - std::vector& colors) const - { - auto disj = top_disjuncts(); - if (! - (has_parity_prefix_aux(new_cond, colors, - top_conjuncts(), acc_cond::acc_op::Fin) || - has_parity_prefix_aux(new_cond, colors, - disj, acc_cond::acc_op::Inf))) - new_cond = spot::acc_cond(*this); - return disj.size() == 2; - } + has_parity_prefix(acc_cond& new_cond, + std::vector& colors) const; bool is_parity_max_equiv(std::vector& permut, @@ -1951,9 +1707,9 @@ namespace spot /// Fin(0)|(Inf(0) & Fin(1)), Inf(0) is true iff Fin(0) is false so /// we can rewrite it as Fin(0)|Fin(1). acc_cond - propagate_fin_inf() + unit_propagation() { - return acc_cond(code_.propagate_fin_inf()); + return acc_cond(code_.unit_propagation()); } // Return (true, m) if there exist some acceptance mark m that diff --git a/spot/twaalgos/cleanacc.cc b/spot/twaalgos/cleanacc.cc index 8a3772c8b..2c4ba0336 100644 --- a/spot/twaalgos/cleanacc.cc +++ b/spot/twaalgos/cleanacc.cc @@ -620,7 +620,7 @@ namespace spot fuse_marks_here(aut); } cleanup_acceptance_here(aut, true); - auto prop_cond = aut->acc().propagate_fin_inf(); + auto prop_cond = aut->acc().unit_propagation(); if (prop_cond != aut->acc()) { aut->set_acceptance(prop_cond);