twaalgos: add a match_states variant with a formula argument

This is related to issue #591, reported by Blake C. Rawlings.

* spot/twaalgos/ltl2tgba_fm.cc, spot/twaalgos/ltl2tgba_fm.hh
(ltl_to_tgba_fm): Add option to keep LTL labels.
* spot/twaalgos/matchstates.cc, spot/twaalgos/matchstates.hh
(match_states): Add variant with a formula as second argument.
* tests/python/matchstates.py: Test it.
* NEWS: Mention it.
* THANKS: Add reporter.
This commit is contained in:
Alexandre Duret-Lutz 2024-08-29 11:16:35 +02:00
parent 5f1d00b858
commit 3d3e87948c
7 changed files with 89 additions and 4 deletions

6
NEWS
View file

@ -62,6 +62,12 @@ New in spot 2.12.0.dev (not yet released)
and B accept the same language, any word accepted by A from state and B accept the same language, any word accepted by A from state
x can be accepted in B from some state in V[x]. x can be accepted in B from some state in V[x].
That function also has a variant spot::match_states(A, f) where f
is an LTL formula. In this case it returns and array of
formulas. If f represents a superset of the language of A, then
any word accepted by A from state x satisfies V[x]. Related to
Issue #591.
Bug fixes: Bug fixes:
- Generating random formulas without any unary opertor would very - Generating random formulas without any unary opertor would very

1
THANKS
View file

@ -5,6 +5,7 @@ Andreas Tollkötter
Andrew Wells Andrew Wells
Anton Pirogov Anton Pirogov
Ayrat Khalimov Ayrat Khalimov
Blake C. Rawlings
Cambridge Yang Cambridge Yang
Caroline Lemieux Caroline Lemieux
Christian Dax Christian Dax

View file

@ -1887,7 +1887,7 @@ namespace spot
bool exprop, bool symb_merge, bool branching_postponement, bool exprop, bool symb_merge, bool branching_postponement,
bool fair_loop_approx, const atomic_prop_set* unobs, bool fair_loop_approx, const atomic_prop_set* unobs,
tl_simplifier* simplifier, bool unambiguous, tl_simplifier* simplifier, bool unambiguous,
const output_aborter* aborter) const output_aborter* aborter, bool label_with_ltl)
{ {
tl_simplifier* s = simplifier; tl_simplifier* s = simplifier;
@ -2216,8 +2216,9 @@ namespace spot
if (orig_f.is_syntactic_guarantee()) if (orig_f.is_syntactic_guarantee())
a->prop_terminal(true); a->prop_terminal(true);
} }
// Set the following to true to preserve state names.
a->release_formula_namer(namer, false); // This gives each state a name of label_with_ltl is set.
a->release_formula_namer(namer, label_with_ltl);
if (!simplifier) if (!simplifier)
// This should not be deleted before we have registered all propositions. // This should not be deleted before we have registered all propositions.

View file

@ -74,6 +74,10 @@ namespace spot
/// constructed automaton would become larger than specified by the /// constructed automaton would become larger than specified by the
/// output_aborter. /// output_aborter.
/// ///
/// \param label_with_ltl keep one LTL formula equivalent the
/// language recognized by each state, and use that to name each
/// state.
///
/// \return A spot::twa_graph that recognizes the language of \a f. /// \return A spot::twa_graph that recognizes the language of \a f.
SPOT_API twa_graph_ptr SPOT_API twa_graph_ptr
ltl_to_tgba_fm(formula f, const bdd_dict_ptr& dict, ltl_to_tgba_fm(formula f, const bdd_dict_ptr& dict,
@ -83,5 +87,6 @@ namespace spot
const atomic_prop_set* unobs = nullptr, const atomic_prop_set* unobs = nullptr,
tl_simplifier* simplifier = nullptr, tl_simplifier* simplifier = nullptr,
bool unambiguous = false, bool unambiguous = false,
const output_aborter* aborter = nullptr); const output_aborter* aborter = nullptr,
bool label_with_ltl = false);
} }

View file

@ -20,6 +20,8 @@
#include <spot/twaalgos/matchstates.hh> #include <spot/twaalgos/matchstates.hh>
#include <spot/twaalgos/sccinfo.hh> #include <spot/twaalgos/sccinfo.hh>
#include <spot/twaalgos/product.hh> #include <spot/twaalgos/product.hh>
#include <spot/twaalgos/ltl2tgba_fm.hh>
#include <spot/tl/parse.hh>
namespace spot namespace spot
{ {
@ -45,6 +47,43 @@ namespace spot
return v; return v;
} }
std::vector<formula>
match_states(const const_twa_graph_ptr& aut1, formula f)
{
twa_graph_ptr aut2 = ltl_to_tgba_fm(f, aut1->get_dict(),
false /* exprop */,
true /* symbolic merge */,
false /* branching postponement */,
false /* fair loop approx. */,
nullptr /* unobs event */,
nullptr /* simplifier */,
false /* unambiguous */,
nullptr /* aborter */,
true /* label with LTL */);
auto state_names =
aut2->get_named_prop<std::vector<std::string>>("state-names");
auto v = match_states(aut1, aut2);
unsigned sz1 = aut1->num_states();
unsigned sz2 = aut2->num_states();
// State are labeled with strings, but we know those strings to
// represent LTL formulas, so convert those.
std::vector<formula> state_formulas;
state_formulas.reserve(sz2);
for (unsigned i = 0; i < sz2; ++i)
state_formulas.push_back(parse_formula((*state_names)[i]));
std::vector<formula> res;
res.reserve(sz1);
std::vector<formula> disjuncts;
for (unsigned i = 0; i < sz1; ++i)
{
disjuncts.clear();
for (unsigned j: v[i])
disjuncts.push_back(state_formulas[j]);
res.push_back(formula::Or(disjuncts));
}
return res;
}
} }

View file

@ -20,6 +20,7 @@
#include <spot/misc/common.hh> #include <spot/misc/common.hh>
#include <spot/twa/fwd.hh> #include <spot/twa/fwd.hh>
#include <spot/tl/formula.hh>
#include <vector> #include <vector>
namespace spot namespace spot
@ -37,4 +38,21 @@ namespace spot
SPOT_API std::vector<std::vector<unsigned>> SPOT_API std::vector<std::vector<unsigned>>
match_states(const const_twa_graph_ptr& aut1, match_states(const const_twa_graph_ptr& aut1,
const const_twa_graph_ptr& aut2); const const_twa_graph_ptr& aut2);
/// \ingroup twa_algorithms \brief match the states of \a aut with
/// formulas "reachable" from \a f.
///
/// The returned vector V assigns each state `x` of \a aut to a
/// formula `V[x]`.
///
/// This translates \a f as an automaton B in which states are labeled
/// by formulas, match the states of \a aut with the states of B, and
/// use that to find formulas associated to each state of \a aut.
///
/// In particular, if the language of \a f is a superset of the
/// language of \a aut, then every word accepted in \a aut from
/// state `x` will satisfy formula `V[x]`. However `V[x]` may
/// accept more than the words accepted from `a` in \a aut.
SPOT_API std::vector<formula>
match_states(const const_twa_graph_ptr& aut, formula f);
} }

View file

@ -60,3 +60,18 @@ m3 = spot.match_states(a, c)
tc.assertEqual(m3, ((), (), (), ())) tc.assertEqual(m3, ((), (), (), ()))
m4 = spot.match_states(c, a) m4 = spot.match_states(c, a)
tc.assertEqual(m4, ((), )) tc.assertEqual(m4, ((), ))
f = spot.formula("Ga | Gb | Gc")
m5 = spot.match_states(a, f)
tc.assertEqual(m5, (f, f, f, f))
m6 = spot.match_states(b, f)
tc.assertEqual(m6, (spot.formula("Gc"),
spot.formula("Gb | Gc"),
spot.formula("Gb"),
spot.formula("Ga"),
spot.formula("Ga | Gc"),
spot.formula("Ga | Gb"),
spot.formula("Ga | Gb | Gc")))
m7 = spot.match_states(c, f) # Note that f is not the formula for c
tc.assertEqual(m7, (spot.formula("0"),))