cleanacc: merge algorithms dealing with included and identical sets
* spot/twaalgos/cleanacc.cc (merge_identical_marks_here, merge_mark, included_marks): Fuse these into ... (simplify_included_marks_here): ... this new function. * NEWS: Mention the fix of issue #406.
This commit is contained in:
parent
a804f964d2
commit
25cb7651fe
2 changed files with 90 additions and 176 deletions
6
NEWS
6
NEWS
|
|
@ -46,12 +46,16 @@ New in spot 2.9.3.dev (not yet released)
|
||||||
kripkecube from a PINS file.
|
kripkecube from a PINS file.
|
||||||
|
|
||||||
- Translations for formulas such as FGp1 & FGp2 &...& FGp32 which
|
- Translations for formulas such as FGp1 & FGp2 &...& FGp32 which
|
||||||
used to take ages are now instantaneous. (See issue #412.)
|
used to take ages are now instantaneous. (Issue #412.)
|
||||||
|
|
||||||
- remove_fin() learned to remove more unnecessary edges by using
|
- remove_fin() learned to remove more unnecessary edges by using
|
||||||
propagate_marks_vector(), both in the general case and in the
|
propagate_marks_vector(), both in the general case and in the
|
||||||
Rabin-like case.
|
Rabin-like case.
|
||||||
|
|
||||||
|
- simplify_acceptance() learned to simplify acceptence formulas of
|
||||||
|
the form Inf(x)&Inf(y) or Fin(x)|Fin(y) when the presence of x
|
||||||
|
always implies that of y. (Issue #406.)
|
||||||
|
|
||||||
Bugs fixed:
|
Bugs fixed:
|
||||||
|
|
||||||
- Handle xor and <-> in a more natural way when translating
|
- Handle xor and <-> in a more natural way when translating
|
||||||
|
|
|
||||||
|
|
@ -76,87 +76,6 @@ namespace spot
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
twa_graph_ptr merge_identical_marks_here(twa_graph_ptr aut)
|
|
||||||
{
|
|
||||||
// /!\ This assumes that the acceptance condition has been
|
|
||||||
// cleaned up first. If some mark appears in the acceptance
|
|
||||||
// condition but not in the automaton, the result is undefined.
|
|
||||||
|
|
||||||
auto& acc = aut->acc();
|
|
||||||
auto& c = acc.get_acceptance();
|
|
||||||
acc_cond::mark_t used_in_cond = c.used_sets();
|
|
||||||
|
|
||||||
if (!used_in_cond)
|
|
||||||
return aut;
|
|
||||||
|
|
||||||
unsigned num_sets = acc.num_sets();
|
|
||||||
std::vector<acc_cond::mark_t> always_together(num_sets);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_sets; ++i)
|
|
||||||
if (used_in_cond.has(i))
|
|
||||||
always_together[i] = used_in_cond;
|
|
||||||
else
|
|
||||||
always_together[i] = acc_cond::mark_t({i});
|
|
||||||
|
|
||||||
acc_cond::mark_t previous_a = {};
|
|
||||||
for (auto& t: aut->edges())
|
|
||||||
{
|
|
||||||
acc_cond::mark_t a = t.acc & used_in_cond;
|
|
||||||
if (a == previous_a)
|
|
||||||
continue;
|
|
||||||
previous_a = a;
|
|
||||||
for (unsigned m: a.sets())
|
|
||||||
{
|
|
||||||
acc_cond::mark_t at = always_together[m];
|
|
||||||
acc_cond::mark_t newm = at & a;
|
|
||||||
|
|
||||||
for (unsigned rem: (at - newm).sets())
|
|
||||||
always_together[rem] -= newm;
|
|
||||||
|
|
||||||
always_together[m] = newm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
acc_cond::mark_t to_remove = {};
|
|
||||||
for (unsigned i = 0; i < num_sets; ++i)
|
|
||||||
{
|
|
||||||
auto oldm = always_together[i];
|
|
||||||
if (oldm == acc_cond::mark_t({i}))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
acc_cond::mark_t newm = oldm.lowest();
|
|
||||||
to_remove |= oldm - newm;
|
|
||||||
always_together[i] = newm;
|
|
||||||
}
|
|
||||||
for (auto& t: aut->edges())
|
|
||||||
t.acc -= to_remove;
|
|
||||||
|
|
||||||
// Replace the marks in the acceptance condition
|
|
||||||
auto pos = &c.back();
|
|
||||||
auto end = &c.front();
|
|
||||||
while (pos > end)
|
|
||||||
{
|
|
||||||
switch (pos->sub.op)
|
|
||||||
{
|
|
||||||
case acc_cond::acc_op::And:
|
|
||||||
case acc_cond::acc_op::Or:
|
|
||||||
--pos;
|
|
||||||
break;
|
|
||||||
case acc_cond::acc_op::Fin:
|
|
||||||
case acc_cond::acc_op::Inf:
|
|
||||||
case acc_cond::acc_op::FinNeg:
|
|
||||||
case acc_cond::acc_op::InfNeg:
|
|
||||||
acc_cond::mark_t replace = pos[-1].mark & to_remove;
|
|
||||||
pos[-1].mark -= replace;
|
|
||||||
for (unsigned m: replace.sets())
|
|
||||||
pos[-1].mark |= always_together[m];
|
|
||||||
pos -= 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return aut;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
acc_cond::acc_code remove_compl_rec(const acc_cond::acc_word* pos,
|
||||||
const std::vector<acc_cond::mark_t>&
|
const std::vector<acc_cond::mark_t>&
|
||||||
|
|
@ -611,114 +530,105 @@ namespace spot
|
||||||
// Now rewrite the acceptance condition, removing all the "to_kill" terms.
|
// Now rewrite the acceptance condition, removing all the "to_kill" terms.
|
||||||
aut->set_acceptance(aut->num_sets(), acc_rewrite_rec(&acccopy.back()));
|
aut->set_acceptance(aut->num_sets(), acc_rewrite_rec(&acccopy.back()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static
|
// If X always occurs when Y is present, Inf({X,Y}) can be
|
||||||
acc_cond::mark_t merge_marks(acc_cond::mark_t colors,
|
// replaced by Inf({Y}).
|
||||||
std::vector<acc_cond::mark_t> inclusions)
|
//
|
||||||
{
|
// If X and Y always occur together, then Inf({X}) and Inf({Y})
|
||||||
bool changed;
|
// can be used interchangeably, so we only keep the smallest one.
|
||||||
do
|
static twa_graph_ptr simplify_included_marks_here(twa_graph_ptr aut)
|
||||||
{
|
{
|
||||||
changed = false;
|
// Compute included_by[i], the set of colors always included
|
||||||
for (unsigned c : colors.sets())
|
unsigned ns = aut->num_sets();
|
||||||
{
|
if (ns <= 1)
|
||||||
if ((inclusions[c] & colors) != acc_cond::mark_t {})
|
return aut;
|
||||||
|
auto& c = aut->acc().get_acceptance();
|
||||||
|
acc_cond::mark_t used_in_cond = c.used_sets();
|
||||||
|
if (!used_in_cond.has_many())
|
||||||
|
return aut;
|
||||||
|
|
||||||
|
std::vector<acc_cond::mark_t> always_with(ns, used_in_cond);
|
||||||
|
acc_cond::mark_t previous_a{};
|
||||||
|
|
||||||
|
for (auto& e: aut->edges())
|
||||||
{
|
{
|
||||||
auto new_colors = (colors - inclusions[c]);
|
// Just avoit the e.acc.sets() loops on marks that we have
|
||||||
if (new_colors != colors)
|
// just seen.
|
||||||
changed = true;
|
if (e.acc == previous_a)
|
||||||
colors = new_colors;
|
continue;
|
||||||
break;
|
previous_a = e.acc;
|
||||||
|
for (auto c : e.acc.sets())
|
||||||
|
always_with[c] &= e.acc;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} while (changed);
|
// For each color n, find the smallest color m that is always used
|
||||||
return colors;
|
// with n. If m != n, record that n must be removed (and replaced
|
||||||
|
// by always_together[m]).
|
||||||
|
std::vector<acc_cond::mark_t> always_together(ns);
|
||||||
|
acc_cond::mark_t to_remove{};
|
||||||
|
for (unsigned n = ns - 1; n > 0; --n)
|
||||||
|
{
|
||||||
|
if (!used_in_cond.has(n))
|
||||||
|
continue;
|
||||||
|
always_together[n].set(n);
|
||||||
|
for (unsigned m = 0; m < n; ++m)
|
||||||
|
if (used_in_cond.has(m) && always_with[n] == always_with[m])
|
||||||
|
{
|
||||||
|
always_together[n] = {m};
|
||||||
|
to_remove.set(n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
always_together[0].set(0);
|
||||||
|
|
||||||
|
for (unsigned n = 0; n < ns; ++n)
|
||||||
|
always_with[n].clear(n);
|
||||||
|
|
||||||
|
// Replace the marks in the acceptance condition
|
||||||
|
// We replace each color X in to_remove by always_together[X],
|
||||||
|
// and remove always_with[Y] for each Y in Inf or Fin.
|
||||||
|
auto pos = &c.back();
|
||||||
|
auto end = &c.front();
|
||||||
|
while (pos > end)
|
||||||
|
{
|
||||||
|
switch (pos->sub.op)
|
||||||
|
{
|
||||||
|
case acc_cond::acc_op::And:
|
||||||
|
case acc_cond::acc_op::Or:
|
||||||
|
--pos;
|
||||||
|
break;
|
||||||
|
case acc_cond::acc_op::Fin:
|
||||||
|
case acc_cond::acc_op::Inf:
|
||||||
|
case acc_cond::acc_op::FinNeg:
|
||||||
|
case acc_cond::acc_op::InfNeg:
|
||||||
|
{
|
||||||
|
acc_cond::mark_t colors = pos[-1].mark;
|
||||||
|
acc_cond::mark_t replace = colors & to_remove;
|
||||||
|
colors -= replace;
|
||||||
|
for (unsigned m: replace.sets())
|
||||||
|
colors |= always_together[m];
|
||||||
|
for (unsigned m: colors.sets())
|
||||||
|
colors -= always_with[m];
|
||||||
|
pos[-1].mark = colors;
|
||||||
|
pos -= 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aut;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
acc_cond::acc_code merge_colors(acc_cond::acc_code code,
|
|
||||||
std::vector<acc_cond::mark_t> inclusions)
|
|
||||||
{
|
|
||||||
if (code.empty())
|
|
||||||
return {};
|
|
||||||
int pos = code.size() - 1;
|
|
||||||
acc_cond::acc_code result;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
switch (code[pos].sub.op)
|
|
||||||
{
|
|
||||||
case acc_cond::acc_op::And:
|
|
||||||
{
|
|
||||||
result = acc_cond::acc_code::t();
|
|
||||||
--pos;
|
|
||||||
while (pos > 0)
|
|
||||||
{
|
|
||||||
result = merge_colors(acc_cond::acc_code(&code[pos]), inclusions)
|
|
||||||
& result;
|
|
||||||
pos -= (code[pos].sub.size + 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
case acc_cond::acc_op::Or:
|
|
||||||
{
|
|
||||||
result = acc_cond::acc_code::f();
|
|
||||||
--pos;
|
|
||||||
while (pos > 0)
|
|
||||||
{
|
|
||||||
result = merge_colors(acc_cond::acc_code(&code[pos]), inclusions)
|
|
||||||
| result;
|
|
||||||
pos -= (code[pos].sub.size + 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
case acc_cond::acc_op::Fin:
|
|
||||||
{
|
|
||||||
auto res = acc_cond::acc_code::fin(merge_marks(code[pos - 1].mark,
|
|
||||||
inclusions));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
case acc_cond::acc_op::Inf:
|
|
||||||
{
|
|
||||||
auto res = acc_cond::acc_code::inf(merge_marks(code[pos - 1].mark,
|
|
||||||
inclusions));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
} while (pos > 0);
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a vector of marks such that for every color c, result[c] contains
|
|
||||||
// all the colors that are on every transitions that also contain c
|
|
||||||
// (c is excluded).
|
|
||||||
static std::vector<acc_cond::mark_t> included_marks(twa_graph_ptr aut)
|
|
||||||
{
|
|
||||||
std::vector<acc_cond::mark_t> result(SPOT_MAX_ACCSETS,
|
|
||||||
acc_cond::mark_t::all());
|
|
||||||
for (unsigned i = 0; i < SPOT_MAX_ACCSETS; ++i)
|
|
||||||
result[i]^= acc_cond::mark_t {i};
|
|
||||||
for (auto& e: aut->edges())
|
|
||||||
for (auto c : e.acc.sets())
|
|
||||||
result[c] &= e.acc;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_graph_ptr simplify_acceptance_here(twa_graph_ptr aut)
|
twa_graph_ptr simplify_acceptance_here(twa_graph_ptr aut)
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
cleanup_acceptance_here(aut, false);
|
cleanup_acceptance_here(aut, false);
|
||||||
merge_identical_marks_here(aut);
|
simplify_included_marks_here(aut);
|
||||||
if (aut->acc().is_generalized_buchi())
|
if (aut->acc().is_generalized_buchi())
|
||||||
break;
|
break;
|
||||||
auto inc = included_marks(aut);
|
acc_cond::acc_code old = aut->get_acceptance();
|
||||||
auto new_code = merge_colors(aut->get_acceptance(), inc);
|
|
||||||
aut->set_acceptance(acc_cond(aut->num_sets(), new_code));
|
|
||||||
acc_cond::acc_code old = new_code;
|
|
||||||
aut->set_acceptance(aut->acc().unit_propagation());
|
aut->set_acceptance(aut->acc().unit_propagation());
|
||||||
simplify_complementary_marks_here(aut);
|
simplify_complementary_marks_here(aut);
|
||||||
fuse_marks_here(aut);
|
fuse_marks_here(aut);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue