product_susp: fix handling of unsatisfiable/universal acceptances

Part of issue #546 reported by Rüdiger Ehlers

* spot/twaalgos/product.cc (product_susp): Fix detection and handling
of unsatisfiable/universal acceptances.
* tests/python/_product_susp.ipynb: Add test cases.
This commit is contained in:
Alexandre Duret-Lutz 2023-11-07 17:17:58 +01:00
parent 127cb89cad
commit ac05035267
3 changed files with 1265 additions and 57 deletions

4
NEWS
View file

@ -112,6 +112,10 @@ New in spot 2.11.6.dev (not yet released)
(Issue #541.) This has been fixed by disabled the use_simulation
optimization in this case.
- product_or_susp() and product_susp() would behave incorrectly in
presence of unsatisifable or universal acceptance conditions that
were not f or t. (Part of issue #546.)
New in spot 2.11.6 (2023-08-01)
Bug fixes:

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2014-2020, 2022 Laboratoire de Recherche et Développement
// Copyright (C) 2014-2020, 2022, 2023 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
@ -607,33 +607,36 @@ namespace spot
throw std::runtime_error("product_susp(): left and right automata "
"should share their bdd_dict");
auto false_or_left = [&] (bool ff)
{
if (ff)
{
auto res = make_twa_graph(left->get_dict());
res->new_state();
res->prop_terminal(true);
res->prop_stutter_invariant(true);
res->prop_universal(true);
res->prop_complete(false);
return res;
}
return make_twa_graph(left, twa::prop_set::all());
};
auto const_automaton = [&left] (bool is_true)
{
auto res = make_twa_graph(left->get_dict());
res->new_state();
res->prop_terminal(true);
res->prop_stutter_invariant(true);
res->prop_universal(true);
res->prop_complete(is_true);
if (is_true)
res->new_edge(0, 0, bddtrue);
return res;
};
// We assume RIGHT is suspendable, but we want to deal with some
// trivial true/false cases so we can later assume right has
// more than one acceptance set.
// Note: suspendable with "t" acceptance = universal language.
if (SPOT_UNLIKELY(right->num_sets() == 0))
if (SPOT_UNLIKELY(right->num_sets() == 0
|| right->num_edges() == 0
|| right->acc().is_t()
|| right->acc().is_f()))
{
if (and_acc)
return false_or_left(right->is_empty());
else if (right->is_empty()) // left OR false = left
trivial:
if (and_acc && right->is_empty())
return const_automaton(false);
else if (!and_acc && !right->is_empty())
// suspendable with "t" acceptance = universal language.
return const_automaton(true);
else // left AND true = left; left OR false = left
return make_twa_graph(left, twa::prop_set::all());
else // left OR true = true
return make_twa_graph(right, twa::prop_set::all());
}
auto res = make_twa_graph(left->get_dict());
@ -644,8 +647,8 @@ namespace spot
res->prop_state_acc(left->prop_state_acc() && right->prop_state_acc());
auto rightunsatmark = right->acc().unsat_mark();
if (SPOT_UNLIKELY(!rightunsatmark.first))
return false_or_left(and_acc);
if (SPOT_UNLIKELY(!rightunsatmark.first)) // right is universal
goto trivial;
acc_cond::mark_t rejmark = rightunsatmark.second;
if (leftweak)

File diff suppressed because it is too large Load diff