postprocess, translate: add support for Büchi (not state-based)

spot/twaalgos/postproc.hh: Introduce options Buchi and
GeneralizedBuchi.  The latter is similar to TGBA but the former differs
from BA in that it does not imply state-based acceptance, since that
can be specified separately.  Also all other acceptance types are not
abbreviated, so those new names make more sense.
* NEWS: Mention that.
* spot/twaalgos/postproc.cc, spot/twaalgos/translate.cc: Adjust
to support Buchi and GeneralizedBuchi without breaking BA and TGBA.
* bin/autfilt.cc, bin/common_aoutput.cc, bin/common_post.cc,
bin/ltl2tgta.cc, doc/org/tut10.org, doc/org/tut12.org,
doc/org/tut30.org, python/spot/__init__.py,
tests/python/automata.ipynb, tests/python/langmap.py,
tests/python/misc-ec.py, tests/python/satmin.ipynb,
tests/python/satmin.py, tests/python/toweak.py: Use the new names.
* tests/Makefile.am: Add missing langmap.py.
This commit is contained in:
Alexandre Duret-Lutz 2020-10-06 17:46:34 +02:00
parent 72c492b0cf
commit 9cc1bdf10f
19 changed files with 274 additions and 201 deletions

View file

@ -48,7 +48,7 @@ namespace spot
static twa_graph_ptr
ensure_ba(twa_graph_ptr& a)
{
if (a->num_sets() == 0)
if (a->acc().is_t())
{
auto m = a->set_buchi();
for (auto& t: a->edges())
@ -154,6 +154,15 @@ namespace spot
}
}
twa_graph_ptr
postprocessor::choose_degen(const twa_graph_ptr& a) const
{
if (state_based_)
return do_degen(a);
else
return do_degen_tba(a);
}
twa_graph_ptr
postprocessor::do_degen(const twa_graph_ptr& a) const
{
@ -173,15 +182,6 @@ namespace spot
degen_lowinit_, degen_remscc_);
}
static void
force_buchi(twa_graph_ptr& a)
{
assert(a->acc().is_t());
acc_cond::mark_t m = a->set_buchi();
for (auto& e: a->edges())
e.acc = m;
}
twa_graph_ptr
postprocessor::do_scc_filter(const twa_graph_ptr& a, bool arg) const
{
@ -212,11 +212,12 @@ namespace spot
tmp = complete(tmp);
bool want_parity = type_ & Parity;
if (want_parity && tmp->acc().is_generalized_buchi())
tmp = SBACC_ ? do_degen(tmp) : do_degen_tba(tmp);
if (SBACC_)
tmp = choose_degen(tmp);
assert(!!SBACC_ == state_based_);
if (state_based_)
tmp = sbacc(tmp);
if (type_ == BA && tmp->acc().is_t())
force_buchi(tmp);
if (type_ == Buchi)
tmp = ensure_ba(tmp);
if (want_parity)
{
reduce_parity_here(tmp, COLORED_);
@ -244,10 +245,18 @@ namespace spot
ba_simul_ = (level_ == High) ? 3 : 0;
if (scc_filter_ < 0)
scc_filter_ = 1;
if (type_ == BA || SBACC_)
if (type_ == BA)
{
pref_ |= SBAcc;
type_ = Buchi;
}
if (SBACC_)
state_based_ = true;
else if (state_based_)
pref_ |= SBAcc;
bool via_gba = (type_ == BA) || (type_ == TGBA) || (type_ == Monitor);
bool via_gba =
(type_ == Buchi) || (type_ == GeneralizedBuchi) || (type_ == Monitor);
bool want_parity = type_ & Parity;
if (COLORED_ && !want_parity)
throw std::runtime_error("postprocessor: the Colored setting only works "
@ -317,8 +326,8 @@ namespace spot
if (PREF_ == Any && level_ == Low
&& (type_ == Generic
|| type_ == TGBA
|| (type_ == BA && a->is_sba())
|| type_ == GeneralizedBuchi
|| (type_ == Buchi && a->acc().is_buchi())
|| (type_ == Monitor && a->num_sets() == 0)
|| (want_parity && a->acc().is_parity())
|| (type_ == CoBuchi && a->acc().is_co_buchi())))
@ -362,8 +371,8 @@ namespace spot
if (PREF_ == Any)
{
if (type_ == BA)
a = do_degen(a);
if (type_ == Buchi)
a = choose_degen(a);
else if (type_ == CoBuchi)
a = to_nca(a);
return finalize(a);
@ -402,8 +411,6 @@ namespace spot
if (!ab && PREF_ != Deterministic)
ab = &wdba_aborter;
dba = minimize_obligation(a, f, nullptr, reject_bigger, ab);
if (!dba)
std::cerr << "DBA aborted\n";
if (dba
&& dba->prop_inherently_weak().is_true()
@ -412,7 +419,7 @@ namespace spot
// The WDBA is a BA, so no degeneralization is required.
// We just need to add an acceptance set if there is none.
dba_is_minimal = dba_is_wdba = true;
if (type_ == BA)
if (type_ == Buchi)
ensure_ba(dba);
}
else
@ -426,9 +433,9 @@ namespace spot
// at hard levels if we want a small output.
if (!dba || (level_ == High && PREF_ == Small))
{
if (((SBACC_ && a->prop_state_acc().is_true())
|| (type_ == BA && a->is_sba()))
&& !tba_determinisation_)
if ((state_based_ && a->prop_state_acc().is_true())
&& !tba_determinisation_
&& (type_ != Buchi || a->acc().is_buchi()))
{
sim = do_sba_simul(a, ba_simul_);
}
@ -437,11 +444,11 @@ namespace spot
sim = do_simul(a, simul_);
// Degeneralize the result of the simulation if needed.
// No need to do that if tba_determinisation_ will be used.
if (type_ == BA && !tba_determinisation_)
sim = do_degen(sim);
if (type_ == Buchi && !tba_determinisation_)
sim = choose_degen(sim);
else if (want_parity && !sim->acc().is_parity())
sim = do_degen_tba(sim);
else if (SBACC_ && !tba_determinisation_)
else if (state_based_ && !tba_determinisation_)
sim = sbacc(sim);
}
}
@ -452,21 +459,16 @@ namespace spot
if (!dba && is_deterministic(sim))
{
std::swap(sim, dba);
// We postponed degeneralization above i case we would need
// We postponed degeneralization above in case we would need
// to perform TBA-determinisation, but now it is clear
// that we won't perform it. So do degeneralize.
if (tba_determinisation_)
{
if (type_ == BA)
{
dba = do_degen(dba);
assert(is_deterministic(dba));
}
else if (SBACC_)
{
dba = sbacc(dba);
assert(is_deterministic(dba));
}
if (type_ == Buchi)
dba = choose_degen(dba);
else if (state_based_)
dba = sbacc(dba);
assert(is_deterministic(dba));
}
}
@ -513,8 +515,8 @@ namespace spot
else
{
// degeneralize sim, because we did not do it earlier
if (type_ == BA)
sim = do_degen(sim);
if (type_ == Buchi)
sim = choose_degen(sim);
}
}
@ -552,7 +554,7 @@ namespace spot
throw std::runtime_error
("postproc() not yet updated to mix sat-minimize and Generic");
unsigned target_acc;
if (type_ == BA)
if (type_ == Buchi)
target_acc = 1;
else if (sat_acc_ != -1)
target_acc = sat_acc_;
@ -634,8 +636,8 @@ namespace spot
// Degeneralize the dba resulting from tba-determinization or
// sat-minimization (which is a TBA) if requested and needed.
if (dba && !dba_is_wdba && type_ == BA
&& !(dba_is_minimal && state_based_ && dba->num_sets() == 1))
if (dba && !dba_is_wdba && type_ == Buchi && state_based_
&& !(dba_is_minimal && dba->num_sets() == 1))
dba = degeneralize(dba);
if (dba && sim)

View file

@ -72,26 +72,29 @@ namespace spot
/// options used for debugging or benchmarking.
postprocessor(const option_map* opt = nullptr);
enum output_type { TGBA = 0, // should be renamed GeneralizedBuchi
BA = 1, // should be renamed Buchi and not imply SBAcc
Monitor = 2,
Generic = 3,
Parity = 4,
ParityMin = Parity | 8,
ParityMax = Parity | 16,
ParityOdd = Parity | 32,
ParityEven = Parity | 64,
ParityMinOdd = ParityMin | ParityOdd,
ParityMaxOdd = ParityMax | ParityOdd,
ParityMinEven = ParityMin | ParityEven,
ParityMaxEven = ParityMax | ParityEven,
CoBuchi = 128,
enum output_type {
TGBA = 0, // Historical. Use GeneralizedBuchi instead
GeneralizedBuchi = 0, // Introduced in Spot 2.10 to replace TGBA
BA = 1, // Historical. Implies Buchi and SBAcc.
Monitor = 2,
Generic = 3,
Parity = 4,
ParityMin = Parity | 8,
ParityMax = Parity | 16,
ParityOdd = Parity | 32,
ParityEven = Parity | 64,
ParityMinOdd = ParityMin | ParityOdd,
ParityMaxOdd = ParityMax | ParityOdd,
ParityMinEven = ParityMin | ParityEven,
ParityMaxEven = ParityMax | ParityEven,
CoBuchi = 128,
Buchi = 256, // introduced in Spot 2.10, does not imply SBAcc
};
/// \brief Select the desired output type.
///
/// \c TGBA requires transition-based generalized Büchi acceptance
/// while \c BA requests state-based Büchi acceptance. In both
/// \c GeneralizedBuchi requires generalized Büchi acceptance
/// while \c Buchi requests Büchi acceptance. In both
/// cases, automata with more complex acceptance conditions will
/// be converted into these simpler acceptance. For references
/// about the algorithms used behind these options, see section 5
@ -116,17 +119,22 @@ namespace spot
/// not all TGBA can be degeneralized, using \c Generic will allow
/// parity acceptance to be used instead).
///
/// \a Parity and its variants request the acceptance condition to
/// \c Parity and its variants request the acceptance condition to
/// be of some parity type. Note that the determinization
/// algorithm used by Spot produces "parity min odd" acceptance,
/// but other parity types can be obtained from there by minor
/// adjustments.
///
/// \a CoBuchi requests a Co-Büchi automaton equivalent to
/// \c CoBuchi requests a Co-Büchi automaton equivalent to
/// the input, when possible, or a Co-Büchi automaton that
/// recognize a larger language otherwise.
///
/// If set_type() is not called, the default \c output_type is \c TGBA.
/// \c BA is a historical type that means Buchi and additionally
/// set state-based acceptance (this should normally be set
/// with `set_pref(SBAcc)`).
///
/// If set_type() is not called, the default \c output_type is \c
/// GeneralizedBuchi.
void
set_type(output_type type)
{
@ -221,6 +229,7 @@ namespace spot
protected:
twa_graph_ptr do_simul(const twa_graph_ptr& input, int opt) const;
twa_graph_ptr do_sba_simul(const twa_graph_ptr& input, int opt) const;
twa_graph_ptr choose_degen(const twa_graph_ptr& input) const;
twa_graph_ptr do_degen(const twa_graph_ptr& input) const;
twa_graph_ptr do_degen_tba(const twa_graph_ptr& input) const;
twa_graph_ptr do_scc_filter(const twa_graph_ptr& a, bool arg) const;

View file

@ -142,7 +142,7 @@ namespace spot
r2 = r2[0];
++leading_x;
}
if (type_ == Generic || type_ == TGBA)
if (type_ == Generic || type_ == GeneralizedBuchi)
{
// F(q|u|f) = q|F(u)|F(f) only for generic acceptance
// G(q&e&f) = q&G(e)&G(f)
@ -174,7 +174,7 @@ namespace spot
// with disjunction, but it seems to generate larger automata
// in many cases and it needs to be further investigated. Maybe
// this could be relaxed in the case of deterministic output.
(!r2.is(op::And) && (type_ == TGBA || type_ == BA)))
(!r2.is(op::And) && (type_ == GeneralizedBuchi || type_ == Buchi)))
goto nosplit;
op topop = r2.kind();
@ -182,7 +182,7 @@ namespace spot
std::vector<formula> oblg;
std::vector<formula> susp;
std::vector<formula> rest;
bool want_g = type_ == TGBA || type_ == BA;
bool want_g = type_ == GeneralizedBuchi || type_ == Buchi;
for (formula child: r2)
{
if (child.is_syntactic_obligation())
@ -213,7 +213,8 @@ namespace spot
{
// The only cases where we accept susp and rest to be both
// non-empty is when doing Generic acceptance or TGBA.
if (!rest.empty() && !(type_ == Generic || type_ == TGBA))
if (!rest.empty()
&& !(type_ == Generic || type_ == GeneralizedBuchi))
{
rest.insert(rest.end(), susp.begin(), susp.end());
susp.clear();
@ -225,7 +226,7 @@ namespace spot
}
// For TGBA and BA, we only split if there is something to
// suspend.
if (susp.empty() && (type_ == TGBA || type_ == BA))
if (susp.empty() && (type_ == GeneralizedBuchi || type_ == Buchi))
goto nosplit;
option_map om_wos;
@ -375,17 +376,19 @@ namespace spot
if (gf_guarantee_ && PREF_ != Any)
{
bool det = unambiguous || (PREF_ == Deterministic);
bool sba = type_ == BA || (pref_ & SBAcc);
if ((type_ & (BA | Parity | Generic)) || type_ == TGBA)
if ((type_ & (Buchi | Parity))
|| type_ == Generic
|| type_ == GeneralizedBuchi)
aut2 = gf_guarantee_to_ba_maybe(r, simpl_->get_dict(),
det, sba);
if (aut2 && ((type_ == BA) || (type_ & Parity))
det, state_based_);
if (aut2 && (type_ & (Buchi | Parity))
&& (pref_ & Deterministic))
return finalize(aut2);
if (!aut2 && (type_ == Generic
|| type_ & (Parity | CoBuchi)))
{
aut2 = fg_safety_to_dca_maybe(r, simpl_->get_dict(), sba);
aut2 = fg_safety_to_dca_maybe(r, simpl_->get_dict(),
state_based_);
if (aut2
&& (type_ & (CoBuchi | Parity))
&& (pref_ & Deterministic))
@ -418,6 +421,16 @@ namespace spot
twa_graph_ptr translator::run(formula* f)
{
if (type_ == BA)
{
pref_ |= SBAcc;
type_ = Buchi;
}
if (pref_ & SBAcc)
state_based_ = true;
else if (state_based_)
pref_ |= SBAcc;
if (simpl_owned_)
{
// Modify the options according to set_pref() and set_type().