cleanacc: keep acceptance order when removing complementary colors

* spot/twaalgos/cleanacc.cc (remove_compl_rec): Rewrite to preserve
the original order of the acceptance condition while rewriting it.
* tests/core/sccdot.test, tests/python/merge.py,
tests/python/simplacc.py, tests/python/toparity.py: Adjust test cases.
This commit is contained in:
Alexandre Duret-Lutz 2020-04-18 22:05:43 +02:00
parent 262b24e6d7
commit c0e1b3e52a
5 changed files with 109 additions and 108 deletions

View file

@ -157,101 +157,99 @@ namespace spot
return aut;
}
// Eventually remove complementary marks from the acceptance condition.
// Remove complementary marks from the acceptance condition.
acc_cond::acc_code remove_compl_rec(const acc_cond::acc_word* pos,
const std::vector<acc_cond::mark_t>&
complement)
{
auto start = pos - pos->sub.size;
auto boolop =
[&](acc_cond::acc_op opand, acc_cond::acc_op opfin,
acc_cond::acc_op opinf,
acc_cond::acc_code&& truecode,
acc_cond::acc_code&& falsecode)
{
--pos;
acc_cond::acc_code res = truecode;
acc_cond::mark_t seen_fin = {};
do
{
auto tmp = remove_compl_rec(pos, complement);
if (!tmp.empty() && (tmp.back().sub.op == opfin
&& tmp.front().mark.count() == 1))
seen_fin |= tmp.front().mark;
if (opand == acc_cond::acc_op::And)
tmp &= std::move(res);
else
tmp |= std::move(res);
std::swap(tmp, res);
pos -= pos->sub.size + 1;
}
while (pos > start);
if (res.empty() || res.back().sub.op != opand)
return res;
// Locate the position of any Inf element.
// A property of the &= operator is that there
// is only one Inf in a conjunction.
auto rbegin = &res.back();
auto rend = rbegin - rbegin->sub.size;
--rbegin;
do
{
if (rbegin->sub.op == opinf)
break;
rbegin -= rbegin->sub.size + 1;
}
while (rbegin > rend);
if (rbegin <= rend)
return res;
// Fin(i) & Inf(i) = f;
if (rbegin[-1].mark & seen_fin)
return std::move(falsecode);
for (auto m: seen_fin.sets())
{
acc_cond::mark_t cm = complement[m];
// Fin(i) & Fin(!i) = f;
if (cm & seen_fin)
return std::move(falsecode);
// Inf({!i}) & Fin({i}) = Fin({i})
rbegin[-1].mark -= complement[m];
}
if (rbegin[-1].mark)
return res;
// Inf(i) has been rewritten as t, we need to remove it. Sigh!
acc_cond::acc_code res2 = std::move(truecode);
rbegin = &res.back() - 1;
do
{
acc_cond::acc_code tmp(rbegin);
if (opand == acc_cond::acc_op::And)
tmp &= std::move(res);
else
tmp |= std::move(res);
std::swap(tmp, res2);
rbegin -= rbegin->sub.size + 1;
}
while (rbegin > rend);
return res2;
};
switch (pos->sub.op)
{
case acc_cond::acc_op::And:
{
--pos;
auto res = acc_cond::acc_code::t();
acc_cond::mark_t seen_fin = {};
auto inf = acc_cond::acc_code::inf({});
do
{
auto tmp = remove_compl_rec(pos, complement);
if (!tmp.empty())
{
if (tmp.back().sub.op == acc_cond::acc_op::Fin
&& tmp.front().mark.count() == 1)
seen_fin |= tmp.front().mark;
if (tmp.back().sub.op == acc_cond::acc_op::Inf)
{
inf &= std::move(tmp);
pos -= pos->sub.size + 1;
continue;
}
}
tmp &= std::move(res);
std::swap(tmp, res);
pos -= pos->sub.size + 1;
}
while (pos > start);
// Fin(i) & Inf(i) = f;
if (inf.front().mark & seen_fin)
return acc_cond::acc_code::f();
for (auto m: seen_fin.sets())
{
acc_cond::mark_t cm = complement[m];
// Fin(i) & Fin(!i) = f;
if (cm & seen_fin)
return acc_cond::acc_code::f();
// Inf({!i}) & Fin({i}) = Fin({i})
inf.front().mark -= complement[m];
}
return inf & res;
}
return boolop(acc_cond::acc_op::And,
acc_cond::acc_op::Fin,
acc_cond::acc_op::Inf,
acc_cond::acc_code::t(),
acc_cond::acc_code::f());
case acc_cond::acc_op::Or:
{
--pos;
auto res = acc_cond::acc_code::f();
acc_cond::mark_t seen_inf = {};
auto fin = acc_cond::acc_code::f();
do
{
auto tmp = remove_compl_rec(pos, complement);
if (!tmp.empty())
{
if (tmp.back().sub.op == acc_cond::acc_op::Inf
&& tmp.front().mark.count() == 1)
seen_inf |= tmp.front().mark;
if (tmp.back().sub.op == acc_cond::acc_op::Fin)
{
fin |= std::move(tmp);
pos -= pos->sub.size + 1;
continue;
}
}
tmp |= std::move(res);
std::swap(tmp, res);
pos -= pos->sub.size + 1;
}
while (pos > start);
// Fin(i) | Inf(i) = t;
if (fin.front().mark & seen_inf)
return acc_cond::acc_code::t();
for (auto m: seen_inf.sets())
{
acc_cond::mark_t cm = complement[m];
// Inf({i}) | Inf({!i}) = t;
if (cm & seen_inf)
return acc_cond::acc_code::t();
// Fin({!i}) | Inf({i}) = Inf({i})
fin.front().mark -= complement[m];
}
return res | fin;
}
return boolop(acc_cond::acc_op::Or,
acc_cond::acc_op::Inf,
acc_cond::acc_op::Fin,
acc_cond::acc_code::f(),
acc_cond::acc_code::t());
case acc_cond::acc_op::Fin:
return acc_cond::acc_code::fin(pos[-1].mark);
case acc_cond::acc_op::Inf: