Move several functions from acc.hh to acc.h

* spot/twa/acc.hh: Remove colors_inf_conj and colors_fin_disj
(unused) and moved get_alone_mark (now find_unit_clause),
propagate_fin_inf (now unit_propagation) and has_parity_prefix
to acc.cc.
* spot/twa/acc.cc: Use a new implementation of unit_propagation
and find_unit_clause.
* spot/twaalgos/cleanacc.cc: Use the new name of
propagate_fin_inf.
This commit is contained in:
Florian Renkin 2020-04-10 18:51:47 +02:00 committed by Alexandre Duret-Lutz
parent 630b8333fe
commit b4db34995f
3 changed files with 178 additions and 262 deletions

View file

@ -1060,6 +1060,60 @@ namespace spot
return res;
}
namespace
{
bool
has_parity_prefix_aux(acc_cond original,
acc_cond &new_cond,
std::vector<unsigned> &colors,
std::vector<acc_cond::acc_code> 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<unsigned> &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<unsigned>& colors) const
@ -1082,18 +1136,6 @@ namespace spot
return result;
}
std::vector<unsigned>
acc_cond::colors_inf_conj(unsigned min_nb_colors)
{
return code_.colors_inf_conj(min_nb_colors);
}
std::vector<unsigned>
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<acc_cond::acc_code> 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 = {};

View file

@ -70,12 +70,6 @@ namespace spot
#endif
public:
std::vector<unsigned>
colors_inf_conj(unsigned min_nb_colors);
std::vector<unsigned>
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<acc_word>
{
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<acc_code> 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<unsigned>
colors_inf_conj(unsigned min_nb_colors = 2)
{
auto result = std::vector<unsigned>();
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<unsigned>
colors_fin_disj(unsigned min_nb_colors = 2)
{
auto result = std::vector<unsigned>();
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<unsigned>& colors, std::vector<acc_code> 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<unsigned>& 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<unsigned>& colors) const;
bool
is_parity_max_equiv(std::vector<int>& 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

View file

@ -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);