From 9377db2e5ed954243c0dca46fbf5ed43c400eeab Mon Sep 17 00:00:00 2001 From: Alexandre Duret-Lutz Date: Wed, 19 Apr 2017 18:46:35 +0200 Subject: [PATCH] sbacc: fix a serious bug Reported by Thibaud Michaud * spot/twaalgos/sbacc.cc: Do not label rejecting SCCs with the empty mark, as it might be accepting. * tests/core/sbacc.test: Add test cases. * NEWS: Mention the bug. --- NEWS | 5 ++++ spot/twaalgos/sbacc.cc | 17 ++++++++++- tests/core/sbacc.test | 65 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 7ae916d9c..39d7047bd 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,11 @@ New in spot 2.3.3.dev (not yet released) - spot::dtwa_complement now simply returns the result of dualize() + Bugs fixed: + + - the transformation to state-based acceptance (spot::sbacc()) was + incorrect on automata where the empty acceptance mark is accepting. + Backward-incompatible changes: - spot::acc_cond::mark_t::operator bool() has been marked as diff --git a/spot/twaalgos/sbacc.cc b/spot/twaalgos/sbacc.cc index 2090a5fd3..552c1e453 100644 --- a/spot/twaalgos/sbacc.cc +++ b/spot/twaalgos/sbacc.cc @@ -22,6 +22,7 @@ #include #include #include +#include namespace spot { @@ -33,6 +34,18 @@ namespace spot throw std::runtime_error ("sbacc() does not support alternation"); + // We will need a mark that is rejecting to mark rejecting states. + // If no such mark exist, our work is actually quite simple: we + // just have to copy the automaton and give it "t" as acceptance + // condition. + auto unsat_mark = old->acc().unsat_mark(); + if (!unsat_mark.first) + { + auto res = make_twa_graph(old, twa::prop_set::all()); + strip_acceptance_here(res); + return res; + } + scc_info si(old); unsigned ns = old->num_states(); @@ -97,7 +110,7 @@ namespace spot { unsigned scc_dst = si.scc_of(t.dst); acc_cond::mark_t acc = 0U; - bool dst_acc = si.is_accepting_scc(scc_dst); + bool dst_acc = !si.is_rejecting_scc(scc_dst); if (maybe_accepting && scc_src == scc_dst) acc = t.acc - common_out[t.src]; else if (dst_acc) @@ -106,6 +119,8 @@ namespace spot acc = one_in[t.dst]; if (dst_acc) acc |= common_out[t.dst]; + else + acc = unsat_mark.second; res->new_edge(one.second, new_state(t.dst, acc), t.cond, one.first.second); } diff --git a/tests/core/sbacc.test b/tests/core/sbacc.test index 8c080d538..ca960a9ae 100755 --- a/tests/core/sbacc.test +++ b/tests/core/sbacc.test @@ -159,3 +159,68 @@ randltl --weak-fairness -n 20 2 | "$ltl2tgba -H %f | $autfilt -H >%O" test 4 = `ltl2tgba -S 'F(a & X(!a &Xb))' --any --stats=%s` + + +# Test case from Thibaud Michaud. This used to fail, because sbacc() +# would remove acceptance marks from all rejecting SCCS... +cat >tm.hoa < out.hoa +autfilt -q --equivalent-to out.hoa tm.hoa + +# Tautological acceptances are converted to "t" +cat >taut.hoa <expect.hoa < out.hoa +diff out.hoa expect.hoa