autfilt: add highlighting options for nondeterminism
Fixes #123. * bin/autfilt.cc: Add options --highlight-nondet-states=NUM, --highlight-nondet-edges=NUM, and --highlight-nondet=NUM. * spot/twaalgos/isdet.cc, spot/twaalgos/isdet.hh (highlight_nondet_states, highlight_nondet_edges): New functions. * tests/core/det.test: Add test cases. * NEWS: Mention them.
This commit is contained in:
parent
39332fb118
commit
b6cd54ab16
5 changed files with 186 additions and 5 deletions
13
NEWS
13
NEWS
|
|
@ -20,6 +20,11 @@ New in spot 2.0.3a (not yet released)
|
||||||
These differ from --ap=RANGE that only consider *declared* atomic
|
These differ from --ap=RANGE that only consider *declared* atomic
|
||||||
propositions, regardless of whether they are actually used.
|
propositions, regardless of whether they are actually used.
|
||||||
|
|
||||||
|
* autfilt has two new options to highlight non-determinism:
|
||||||
|
--highlight-nondet-states=NUM and --highlight-nondet-states=NUM
|
||||||
|
where NUM is a color number. Additionally --highlight-nondet=NUM
|
||||||
|
is a shorthand for using the two.
|
||||||
|
|
||||||
* ltlcross and ltldo have a new syntax to specify that an input
|
* ltlcross and ltldo have a new syntax to specify that an input
|
||||||
formula should be written in some given syntax after rewriting
|
formula should be written in some given syntax after rewriting
|
||||||
some operators away. For instance the defaults arguments passed
|
some operators away. For instance the defaults arguments passed
|
||||||
|
|
@ -61,9 +66,13 @@ New in spot 2.0.3a (not yet released)
|
||||||
was secretly able of reading that since 1.99.8, but that is now
|
was secretly able of reading that since 1.99.8, but that is now
|
||||||
documented at https://spot.lrde.epita.fr/hoa.html#extensions
|
documented at https://spot.lrde.epita.fr/hoa.html#extensions
|
||||||
|
|
||||||
|
* highlight_nondet_states() and highlight_nondet_edges() are
|
||||||
|
new functions that define the above two named properties.
|
||||||
|
|
||||||
* is_deterministic(), is_terminal(), is_weak(), and
|
* is_deterministic(), is_terminal(), is_weak(), and
|
||||||
is_inherently_weak(), count_nondet_states() will update the
|
is_inherently_weak(), count_nondet_states(),
|
||||||
corresponding properties of the automaton as a side-effect of
|
highlight_nondet_edges(), highlight_nondet_states() will update
|
||||||
|
the corresponding properties of the automaton as a side-effect of
|
||||||
their check.
|
their check.
|
||||||
|
|
||||||
* language_containment_checker now has default values for all
|
* language_containment_checker now has default values for all
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,9 @@ enum {
|
||||||
OPT_EQUIVALENT_TO,
|
OPT_EQUIVALENT_TO,
|
||||||
OPT_EXCLUSIVE_AP,
|
OPT_EXCLUSIVE_AP,
|
||||||
OPT_GENERIC,
|
OPT_GENERIC,
|
||||||
|
OPT_HIGHLIGHT_NONDET,
|
||||||
|
OPT_HIGHLIGHT_NONDET_EDGES,
|
||||||
|
OPT_HIGHLIGHT_NONDET_STATES,
|
||||||
OPT_INSTUT,
|
OPT_INSTUT,
|
||||||
OPT_INCLUDED_IN,
|
OPT_INCLUDED_IN,
|
||||||
OPT_INHERENTLY_WEAK_SCCS,
|
OPT_INHERENTLY_WEAK_SCCS,
|
||||||
|
|
@ -201,6 +204,16 @@ static const argp_option options[] =
|
||||||
{ "sat-minimize", OPT_SAT_MINIMIZE, "options", OPTION_ARG_OPTIONAL,
|
{ "sat-minimize", OPT_SAT_MINIMIZE, "options", OPTION_ARG_OPTIONAL,
|
||||||
"minimize the automaton using a SAT solver (only works for deterministic"
|
"minimize the automaton using a SAT solver (only works for deterministic"
|
||||||
" automata)", 0 },
|
" automata)", 0 },
|
||||||
|
{ "highlight-nondet-states", OPT_HIGHLIGHT_NONDET_STATES, "NUM",
|
||||||
|
OPTION_ARG_OPTIONAL, "highlight nondeterministic states with color NUM",
|
||||||
|
0},
|
||||||
|
{ "highlight-nondet-edges", OPT_HIGHLIGHT_NONDET_EDGES, "NUM",
|
||||||
|
OPTION_ARG_OPTIONAL, "highlight nondeterministic edges with color NUM",
|
||||||
|
0},
|
||||||
|
{ "highlight-nondet", OPT_HIGHLIGHT_NONDET, "NUM",
|
||||||
|
OPTION_ARG_OPTIONAL,
|
||||||
|
"highlight nondeterministic states and edges with color NUM", 0},
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
{ nullptr, 0, nullptr, 0, "Filtering options:", 6 },
|
{ nullptr, 0, nullptr, 0, "Filtering options:", 6 },
|
||||||
{ "ap", OPT_AP_N, "RANGE", 0,
|
{ "ap", OPT_AP_N, "RANGE", 0,
|
||||||
|
|
@ -382,6 +395,8 @@ static bool opt_rem_unreach = false;
|
||||||
static bool opt_rem_unused_ap = false;
|
static bool opt_rem_unused_ap = false;
|
||||||
static bool opt_sep_sets = false;
|
static bool opt_sep_sets = false;
|
||||||
static const char* opt_sat_minimize = nullptr;
|
static const char* opt_sat_minimize = nullptr;
|
||||||
|
static int opt_highlight_nondet_states = -1;
|
||||||
|
static int opt_highlight_nondet_edges = -1;
|
||||||
|
|
||||||
static spot::twa_graph_ptr
|
static spot::twa_graph_ptr
|
||||||
ensure_deterministic(const spot::twa_graph_ptr& aut)
|
ensure_deterministic(const spot::twa_graph_ptr& aut)
|
||||||
|
|
@ -485,6 +500,18 @@ parse_opt(int key, char* arg, struct argp_state*)
|
||||||
opt->equivalent_neg =
|
opt->equivalent_neg =
|
||||||
spot::dtwa_complement(ensure_deterministic(opt->equivalent_pos));
|
spot::dtwa_complement(ensure_deterministic(opt->equivalent_pos));
|
||||||
break;
|
break;
|
||||||
|
case OPT_HIGHLIGHT_NONDET:
|
||||||
|
{
|
||||||
|
int v = arg ? to_pos_int(arg) : 1;
|
||||||
|
opt_highlight_nondet_edges = opt_highlight_nondet_states = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPT_HIGHLIGHT_NONDET_STATES:
|
||||||
|
opt_highlight_nondet_states = arg ? to_pos_int(arg) : 1;
|
||||||
|
break;
|
||||||
|
case OPT_HIGHLIGHT_NONDET_EDGES:
|
||||||
|
opt_highlight_nondet_edges = arg ? to_pos_int(arg) : 1;
|
||||||
|
break;
|
||||||
case OPT_INSTUT:
|
case OPT_INSTUT:
|
||||||
if (!arg || (arg[0] == '1' && arg[1] == 0))
|
if (!arg || (arg[0] == '1' && arg[1] == 0))
|
||||||
opt_instut = 1;
|
opt_instut = 1;
|
||||||
|
|
@ -929,6 +956,11 @@ namespace
|
||||||
if (randomize_st || randomize_tr)
|
if (randomize_st || randomize_tr)
|
||||||
spot::randomize(aut, randomize_st, randomize_tr);
|
spot::randomize(aut, randomize_st, randomize_tr);
|
||||||
|
|
||||||
|
if (opt_highlight_nondet_states >= 0)
|
||||||
|
spot::highlight_nondet_states(aut, opt_highlight_nondet_states);
|
||||||
|
if (opt_highlight_nondet_edges >= 0)
|
||||||
|
spot::highlight_nondet_edges(aut, opt_highlight_nondet_edges);
|
||||||
|
|
||||||
const double conversion_time = sw.stop();
|
const double conversion_time = sw.stop();
|
||||||
|
|
||||||
if (opt->uniq)
|
if (opt->uniq)
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,53 @@ namespace spot
|
||||||
return !count_nondet_states_aux<false>(aut);
|
return !count_nondet_states_aux<false>(aut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
highlight_nondet_states(twa_graph_ptr& aut, unsigned color)
|
||||||
|
{
|
||||||
|
if (aut->prop_deterministic())
|
||||||
|
return;
|
||||||
|
unsigned ns = aut->num_states();
|
||||||
|
auto* highlight = new std::map<unsigned, unsigned>;
|
||||||
|
for (unsigned src = 0; src < ns; ++src)
|
||||||
|
{
|
||||||
|
bdd available = bddtrue;
|
||||||
|
for (auto& t: aut->out(src))
|
||||||
|
if (!bdd_implies(t.cond, available))
|
||||||
|
highlight->emplace(src, color);
|
||||||
|
else
|
||||||
|
available -= t.cond;
|
||||||
|
}
|
||||||
|
aut->prop_deterministic(highlight->empty());
|
||||||
|
aut->set_named_prop("highlight-states", highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
highlight_nondet_edges(twa_graph_ptr& aut, unsigned color)
|
||||||
|
{
|
||||||
|
if (aut->prop_deterministic())
|
||||||
|
return;
|
||||||
|
unsigned ns = aut->num_states();
|
||||||
|
auto* highlight = new std::map<unsigned, unsigned>;
|
||||||
|
for (unsigned src = 0; src < ns; ++src)
|
||||||
|
{
|
||||||
|
// Make a first pass to gather non-deterministic labels
|
||||||
|
bdd available = bddtrue;
|
||||||
|
bdd extra = bddfalse;
|
||||||
|
for (auto& t: aut->out(src))
|
||||||
|
if (!bdd_implies(t.cond, available))
|
||||||
|
extra |= (t.cond - available);
|
||||||
|
else
|
||||||
|
available -= t.cond;
|
||||||
|
// Second pass to gather the relevant edges.
|
||||||
|
if (extra != bddfalse)
|
||||||
|
for (auto& t: aut->out(src))
|
||||||
|
if ((t.cond & extra) != bddfalse)
|
||||||
|
highlight->emplace(aut->get_graph().index_of_edge(t), color);
|
||||||
|
}
|
||||||
|
aut->prop_deterministic(highlight->empty());
|
||||||
|
aut->set_named_prop("highlight-edges", highlight);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_complete(const const_twa_graph_ptr& aut)
|
is_complete(const const_twa_graph_ptr& aut)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,32 @@ namespace spot
|
||||||
SPOT_API bool
|
SPOT_API bool
|
||||||
is_deterministic(const const_twa_graph_ptr& aut);
|
is_deterministic(const const_twa_graph_ptr& aut);
|
||||||
|
|
||||||
|
/// \brief Highlight nondeterministic states
|
||||||
|
///
|
||||||
|
/// A state is nondeterministic if it has two outgoing edges whose
|
||||||
|
/// labels are not incompatibles.
|
||||||
|
///
|
||||||
|
/// \param aut the automaton to process
|
||||||
|
/// \param color the color to give to nondeterministic states.
|
||||||
|
SPOT_API void
|
||||||
|
highlight_nondet_states(twa_graph_ptr& aut, unsigned color);
|
||||||
|
|
||||||
|
/// \brief Highlight nondeterministic edges
|
||||||
|
///
|
||||||
|
/// An edge is nondeterministic if there exist another edge leaving
|
||||||
|
/// the same source state, with a compatible label (i.e., the
|
||||||
|
/// conjunction of the two labels is not false).
|
||||||
|
///
|
||||||
|
/// \param aut the automaton to process
|
||||||
|
/// \param color the color to give to nondeterministic edges.
|
||||||
|
SPOT_API void
|
||||||
|
highlight_nondet_edges(twa_graph_ptr& aut, unsigned color);
|
||||||
|
/// @}
|
||||||
|
|
||||||
/// \brief Return true iff \a aut is complete.
|
/// \brief Return true iff \a aut is complete.
|
||||||
///
|
///
|
||||||
/// An automaton is complete if its translation relation is total,
|
/// An automaton is complete if its translation relation is total,
|
||||||
/// i.e., each state as a successor for any possible configuration.
|
/// i.e., each state as a successor for any possible configuration.
|
||||||
SPOT_API bool
|
SPOT_API bool
|
||||||
is_complete(const const_twa_graph_ptr& aut);
|
is_complete(const const_twa_graph_ptr& aut);
|
||||||
|
|
||||||
/// @}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
|
# Copyright (C) 2013, 2014, 2015, 2016 Laboratoire de Recherche et
|
||||||
# Développement de l'Epita (LRDE).
|
# Développement de l'Epita (LRDE).
|
||||||
#
|
#
|
||||||
# This file is part of Spot, a model checking library.
|
# This file is part of Spot, a model checking library.
|
||||||
|
|
@ -141,6 +141,79 @@ diff out.tgba ex.tgba
|
||||||
run 0 ltl2tgba -H '(0 R Xa) R (a xor Fa)' > out.hoa
|
run 0 ltl2tgba -H '(0 R Xa) R (a xor Fa)' > out.hoa
|
||||||
grep deterministic out.hoa && exit 1
|
grep deterministic out.hoa && exit 1
|
||||||
|
|
||||||
|
# We can highlight nondeterminism
|
||||||
|
autfilt -H1.1 --highlight-nondet-states=1 \
|
||||||
|
--highlight-nondet-edges=2 out.hoa >out-nd.hoa
|
||||||
|
cat >expected-nd.hoa <<EOF
|
||||||
|
HOA: v1.1
|
||||||
|
name: "XGa R (!a & Fa)"
|
||||||
|
States: 2
|
||||||
|
Start: 1
|
||||||
|
AP: 1 "a"
|
||||||
|
acc-name: Buchi
|
||||||
|
Acceptance: 1 Inf(0)
|
||||||
|
properties: trans-labels explicit-labels state-acc !complete
|
||||||
|
properties: !deterministic
|
||||||
|
spot.highlight.states: 1 1
|
||||||
|
spot.highlight.edges: 2 2 3 2
|
||||||
|
--BODY--
|
||||||
|
State: 0 {0}
|
||||||
|
[0] 0
|
||||||
|
State: 1
|
||||||
|
[!0] 0
|
||||||
|
[!0] 1
|
||||||
|
--END--
|
||||||
|
EOF
|
||||||
|
diff expected-nd.hoa out-nd.hoa
|
||||||
|
|
||||||
|
# While we are at it, make sure randomize preserves highlighted states
|
||||||
|
# (but not highlighted edges, at least until someone implement it).
|
||||||
|
autfilt -H1.1 --seed=3 --randomize out-nd.hoa > rand.hoa
|
||||||
|
cat >expected-rand.hoa <<EOF
|
||||||
|
HOA: v1.1
|
||||||
|
name: "XGa R (!a & Fa)"
|
||||||
|
States: 2
|
||||||
|
Start: 0
|
||||||
|
AP: 1 "a"
|
||||||
|
acc-name: Buchi
|
||||||
|
Acceptance: 1 Inf(0)
|
||||||
|
properties: trans-labels explicit-labels state-acc !complete
|
||||||
|
properties: !deterministic
|
||||||
|
spot.highlight.states: 0 1
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0] 0
|
||||||
|
[!0] 1
|
||||||
|
State: 1 {0}
|
||||||
|
[0] 1
|
||||||
|
--END--
|
||||||
|
EOF
|
||||||
|
diff expected-rand.hoa rand.hoa
|
||||||
|
|
||||||
|
# --highlight-nondet=N is a short for
|
||||||
|
# --highlight-nondet-states=N --highlight-nondet-edges=N
|
||||||
|
autfilt -H1.1 --seed=3 --randomize --highlight-nondet=5 out-nd.hoa > rand2.hoa
|
||||||
|
cat >expected-rand2.hoa <<EOF
|
||||||
|
HOA: v1.1
|
||||||
|
name: "XGa R (!a & Fa)"
|
||||||
|
States: 2
|
||||||
|
Start: 0
|
||||||
|
AP: 1 "a"
|
||||||
|
acc-name: Buchi
|
||||||
|
Acceptance: 1 Inf(0)
|
||||||
|
properties: trans-labels explicit-labels state-acc !complete
|
||||||
|
properties: !deterministic
|
||||||
|
spot.highlight.states: 0 5
|
||||||
|
spot.highlight.edges: 1 5 2 5
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0] 0
|
||||||
|
[!0] 1
|
||||||
|
State: 1 {0}
|
||||||
|
[0] 1
|
||||||
|
--END--
|
||||||
|
EOF
|
||||||
|
diff expected-rand2.hoa rand2.hoa
|
||||||
|
|
||||||
# These highlighted a bug in the bitvector routines because their
|
# These highlighted a bug in the bitvector routines because their
|
||||||
# state count is a multiple of 64.
|
# state count is a multiple of 64.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue