overhaul the stutter-invariance checks
* spot/twaalgos/stutter.cc, spot/twaalgos/stutter.hh: Cleanup and document the api. * spot/twa/twa.hh, doc/mainpage.dox: Add a stutter-invariant section. * tests/python/stutter-inv-states.ipynb: Rename as ... * tests/python/stutter-inv.ipynb: ... this, and add more comments. * tests/Makefile.am, doc/org/tut.org: Adjust renaming. * bench/stutter/stutter_invariance_randomgraph.cc, bench/stutter/stutter_invariance_formulas.cc, bench/stutter/Makefile.am: Make it compile again. * bin/autfilt.cc: Call inplace variants. * NEWS: Mention the overhaul.
This commit is contained in:
parent
2222661f98
commit
6459877a1a
12 changed files with 1169 additions and 882 deletions
12
NEWS
12
NEWS
|
|
@ -126,6 +126,10 @@ New in spot 2.4.1.dev (not yet released)
|
||||||
can be passed to disable this behavior (or use -x degen-remscc=0
|
can be passed to disable this behavior (or use -x degen-remscc=0
|
||||||
from the command-line).
|
from the command-line).
|
||||||
|
|
||||||
|
- The functions for detecting stutter-invariant formulas or automata
|
||||||
|
have been overhauled. Their interface changed slightly. They are
|
||||||
|
now fully documented.
|
||||||
|
|
||||||
- In addition to detecting stutter-invariant formulas/automata, some
|
- In addition to detecting stutter-invariant formulas/automata, some
|
||||||
can now study a stutter-sensitive automaton and detect the subset
|
can now study a stutter-sensitive automaton and detect the subset
|
||||||
of states that are stutter-invariant. See
|
of states that are stutter-invariant. See
|
||||||
|
|
@ -146,6 +150,14 @@ New in spot 2.4.1.dev (not yet released)
|
||||||
spot::scc_info::marks(), spot::scc_info::marks_of() and
|
spot::scc_info::marks(), spot::scc_info::marks_of() and
|
||||||
spot::scc_info::acc_sets_of() respectively.
|
spot::scc_info::acc_sets_of() respectively.
|
||||||
|
|
||||||
|
Backward incompatible changes:
|
||||||
|
|
||||||
|
- The spot::closure(), spot::sl2(), spot::is_stutter_invariant()
|
||||||
|
functions no longuer takes && arguments. The former two have
|
||||||
|
spot::closure_inplace() and spot::sl2_inplace() variant. These
|
||||||
|
function also do not take to list of atomic propositions as an
|
||||||
|
argument anymore.
|
||||||
|
|
||||||
Bugs fixed:
|
Bugs fixed:
|
||||||
|
|
||||||
- Automata produced by "genaut --ks-nca=N" were incorrectly marked
|
- Automata produced by "genaut --ks-nca=N" were incorrectly marked
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
## -*- coding: utf-8 -*-
|
## -*- coding: utf-8 -*-
|
||||||
## Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement
|
## Copyright (C) 2014, 2015, 2017 Laboratoire de Recherche et Développement
|
||||||
## de l'Epita (LRDE).
|
## de l'Epita (LRDE).
|
||||||
##
|
##
|
||||||
## This file is part of Spot, a model checking library.
|
## This file is part of Spot, a model checking library.
|
||||||
|
|
@ -24,7 +24,8 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS)
|
||||||
LDADD = \
|
LDADD = \
|
||||||
$(top_builddir)/bin/libcommon.a \
|
$(top_builddir)/bin/libcommon.a \
|
||||||
$(top_builddir)/lib/libgnu.la \
|
$(top_builddir)/lib/libgnu.la \
|
||||||
$(top_builddir)/spot/libspot.la
|
$(top_builddir)/spot/libspot.la \
|
||||||
|
$(top_builddir)/buddy/src/libbddx.la
|
||||||
|
|
||||||
bin_PROGRAMS = stutter_invariance_randomgraph \
|
bin_PROGRAMS = stutter_invariance_randomgraph \
|
||||||
stutter_invariance_formulas
|
stutter_invariance_formulas
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2014, 2015, 2016 Laboratoire de Recherche et
|
// Copyright (C) 2014, 2015, 2016, 2017 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.
|
||||||
|
|
@ -66,9 +66,8 @@ namespace
|
||||||
spot::twa_graph_ptr a = trans.run(f);
|
spot::twa_graph_ptr a = trans.run(f);
|
||||||
spot::twa_graph_ptr na = trans.run(spot::formula::Not(f));
|
spot::twa_graph_ptr na = trans.run(spot::formula::Not(f));
|
||||||
spot::atomic_prop_set* ap = spot::atomic_prop_collect(f);
|
spot::atomic_prop_set* ap = spot::atomic_prop_collect(f);
|
||||||
bdd apdict = spot::atomic_prop_collect_as_bdd(f, a);
|
|
||||||
|
|
||||||
std::cout << formula << ',' << ap->size() << ',';
|
std::cout << formula << ',' << ap->size() << ',';
|
||||||
|
delete ap;
|
||||||
stats.print(a);
|
stats.print(a);
|
||||||
stats.print(na);
|
stats.print(na);
|
||||||
|
|
||||||
|
|
@ -82,9 +81,9 @@ namespace
|
||||||
sw.start();
|
sw.start();
|
||||||
bool res = spot::is_stutter_invariant(std::move(dup_a),
|
bool res = spot::is_stutter_invariant(std::move(dup_a),
|
||||||
std::move(dup_na),
|
std::move(dup_na),
|
||||||
apdict, algo);
|
algo);
|
||||||
auto time = sw.stop();
|
auto time = sw.stop();
|
||||||
std::cout<< time << ',';
|
std::cout << time << ',';
|
||||||
|
|
||||||
if (algo > 1 && prev != res)
|
if (algo > 1 && prev != res)
|
||||||
{
|
{
|
||||||
|
|
@ -96,7 +95,6 @@ namespace
|
||||||
prev = res;
|
prev = res;
|
||||||
}
|
}
|
||||||
std::cout << prev << '\n';
|
std::cout << prev << '\n';
|
||||||
delete ap;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2014, 2015 Laboratoire de Recherche et
|
// Copyright (C) 2014, 2015, 2017 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.
|
||||||
|
|
@ -77,8 +77,7 @@ main(int argc, char** argv)
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
spot::srand(++seed);
|
spot::srand(++seed);
|
||||||
a = spot::random_graph(states_n, d, &ap, dict, 2, 0.1, 0.5,
|
a = spot::random_graph(states_n, d, &ap, dict, 2, 0.1, 0.5, true);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
while (a->is_empty());
|
while (a->is_empty());
|
||||||
auto na = spot::remove_fin(spot::dualize(a));
|
auto na = spot::remove_fin(spot::dualize(a));
|
||||||
|
|
@ -102,7 +101,7 @@ main(int argc, char** argv)
|
||||||
sw.start();
|
sw.start();
|
||||||
bool res = spot::is_stutter_invariant(std::move(dup_a),
|
bool res = spot::is_stutter_invariant(std::move(dup_a),
|
||||||
std::move(dup_na),
|
std::move(dup_na),
|
||||||
apdict, algo);
|
algo);
|
||||||
auto time = sw.stop();
|
auto time = sw.stop();
|
||||||
std::cout << time;
|
std::cout << time;
|
||||||
if (algo > 1 && res != prev)
|
if (algo > 1 && res != prev)
|
||||||
|
|
|
||||||
|
|
@ -1160,11 +1160,11 @@ namespace
|
||||||
aut = opt->excl_ap.constrain(aut, false);
|
aut = opt->excl_ap.constrain(aut, false);
|
||||||
|
|
||||||
if (opt_destut)
|
if (opt_destut)
|
||||||
aut = spot::closure(std::move(aut));
|
aut = spot::closure_inplace(std::move(aut));
|
||||||
if (opt_instut == 1)
|
if (opt_instut == 1)
|
||||||
aut = spot::sl(std::move(aut));
|
aut = spot::sl(std::move(aut));
|
||||||
else if (opt_instut == 2)
|
else if (opt_instut == 2)
|
||||||
aut = spot::sl2(std::move(aut));
|
aut = spot::sl2_inplace(std::move(aut));
|
||||||
|
|
||||||
if (!opt_keep_states.empty())
|
if (!opt_keep_states.empty())
|
||||||
aut = mask_keep_accessible_states(aut, opt_keep_states,
|
aut = mask_keep_accessible_states(aut, opt_keep_states,
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,12 @@
|
||||||
///
|
///
|
||||||
/// \section pointers Handy starting points
|
/// \section pointers Handy starting points
|
||||||
///
|
///
|
||||||
/// \li spot::formula Base class for an LTL or PSL formula.
|
/// \li spot::formula Base class for an LTL or PSL formula.
|
||||||
/// \li spot::parse_infix_psl() Parsing a text string into a
|
/// \li spot::parse_infix_psl() Parsing a text string into a
|
||||||
/// spot::formula.
|
/// spot::formula.
|
||||||
/// \li spot::twa Base class for Transition-based
|
/// \li spot::twa Base class for Transition-based
|
||||||
/// ω-Automata.
|
/// ω-Automata.
|
||||||
|
/// \li spot::twa_algorithms Algorithms on ω-Automata.
|
||||||
/// \li spot::translator Convert a spot::formula into a
|
/// \li spot::translator Convert a spot::formula into a
|
||||||
/// spot::twa.
|
/// spot::twa.
|
||||||
/// \li spot::kripke Base class for Kripke structures.
|
/// \li spot::kripke Base class for Kripke structures.
|
||||||
|
|
|
||||||
|
|
@ -83,4 +83,4 @@ real notebooks instead.
|
||||||
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2a.html][=atva16-fig2a.ipynb=]] first example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
|
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2a.html][=atva16-fig2a.ipynb=]] first example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
|
||||||
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][=atva16-fig2b.ipynb=]] second example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
|
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][=atva16-fig2b.ipynb=]] second example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
|
||||||
- [[https://spot.lrde.epita.fr/ipynb/alternation.html][=alternation.ipynb=]] examples of alternating automata.
|
- [[https://spot.lrde.epita.fr/ipynb/alternation.html][=alternation.ipynb=]] examples of alternating automata.
|
||||||
- [[https://spot.lrde.epita.fr/ipynb/stutter-inv-states.html][=stutter-inv-states.ipynb=]] detecting stutter-invariant formulas and states.
|
- [[https://spot.lrde.epita.fr/ipynb/stutter-inv.html][=stutter-inv.ipynb=]] working with stutter-invariant formulas properties.
|
||||||
|
|
|
||||||
|
|
@ -1687,6 +1687,9 @@ namespace spot
|
||||||
/// \addtogroup twa_io Input/Output of TωA
|
/// \addtogroup twa_io Input/Output of TωA
|
||||||
/// \ingroup twa_algorithms
|
/// \ingroup twa_algorithms
|
||||||
|
|
||||||
|
/// \addtogroup stutter_inv Stutter-invariance checks
|
||||||
|
/// \ingroup twa_algorithms
|
||||||
|
|
||||||
/// \addtogroup twa_ltl Translating LTL formulas into TωA
|
/// \addtogroup twa_ltl Translating LTL formulas into TωA
|
||||||
/// \ingroup twa_algorithms
|
/// \ingroup twa_algorithms
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -210,12 +210,11 @@ namespace spot
|
||||||
class tgbasl final : public twa
|
class tgbasl final : public twa
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tgbasl(const const_twa_ptr& a, bdd atomic_propositions)
|
tgbasl(const_twa_ptr a)
|
||||||
: twa(a->get_dict()), a_(a), aps_(atomic_propositions)
|
: twa(a->get_dict()), a_(a)
|
||||||
{
|
{
|
||||||
get_dict()->register_all_propositions_of(&a_, this);
|
copy_ap_of(a);
|
||||||
assert(num_sets() == 0);
|
copy_acceptance_of(a_);
|
||||||
set_generalized_buchi(a_->num_sets());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const state* get_init_state() const override
|
virtual const state* get_init_state() const override
|
||||||
|
|
@ -227,7 +226,7 @@ namespace spot
|
||||||
{
|
{
|
||||||
const state_tgbasl* s = down_cast<const state_tgbasl*>(state);
|
const state_tgbasl* s = down_cast<const state_tgbasl*>(state);
|
||||||
return new twasl_succ_iterator(a_->succ_iter(s->real_state()), s,
|
return new twasl_succ_iterator(a_->succ_iter(s->real_state()), s,
|
||||||
a_->get_dict(), aps_);
|
a_->get_dict(), ap_vars());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string format_state(const state* state) const override
|
virtual std::string format_state(const state* state) const override
|
||||||
|
|
@ -240,14 +239,13 @@ namespace spot
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const_twa_ptr a_;
|
const_twa_ptr a_;
|
||||||
bdd aps_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<tgbasl> tgbasl_ptr;
|
typedef std::shared_ptr<tgbasl> tgbasl_ptr;
|
||||||
|
|
||||||
inline tgbasl_ptr make_tgbasl(const const_twa_ptr& aut, bdd ap)
|
inline tgbasl_ptr make_tgbasl(const const_twa_ptr& aut)
|
||||||
{
|
{
|
||||||
return std::make_shared<tgbasl>(aut, ap);
|
return std::make_shared<tgbasl>(aut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -272,22 +270,11 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_graph_ptr
|
||||||
sl(const twa_graph_ptr& a)
|
sl(const_twa_graph_ptr a)
|
||||||
{
|
|
||||||
return sl(a, a->ap_vars());
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_graph_ptr
|
|
||||||
sl2(const twa_graph_ptr& a)
|
|
||||||
{
|
|
||||||
return sl2(a, a->ap_vars());
|
|
||||||
}
|
|
||||||
|
|
||||||
twa_graph_ptr
|
|
||||||
sl(const const_twa_graph_ptr& a, bdd atomic_propositions)
|
|
||||||
{
|
{
|
||||||
// The result automaton uses numbered states.
|
// The result automaton uses numbered states.
|
||||||
twa_graph_ptr res = make_twa_graph(a->get_dict());
|
twa_graph_ptr res = make_twa_graph(a->get_dict());
|
||||||
|
bdd atomic_propositions = a->ap_vars();
|
||||||
// We use the same BDD variables as the input.
|
// We use the same BDD variables as the input.
|
||||||
res->copy_ap_of(a);
|
res->copy_ap_of(a);
|
||||||
res->copy_acceptance_of(a);
|
res->copy_acceptance_of(a);
|
||||||
|
|
@ -348,10 +335,9 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_graph_ptr
|
||||||
sl2(twa_graph_ptr&& a, bdd atomic_propositions)
|
sl2_inplace(twa_graph_ptr a)
|
||||||
{
|
{
|
||||||
if (atomic_propositions == bddfalse)
|
bdd atomic_propositions = a->ap_vars();
|
||||||
atomic_propositions = a->ap_vars();
|
|
||||||
unsigned num_states = a->num_states();
|
unsigned num_states = a->num_states();
|
||||||
unsigned num_edges = a->num_edges();
|
unsigned num_edges = a->num_edges();
|
||||||
std::vector<bdd> selfloops(num_states, bddfalse);
|
std::vector<bdd> selfloops(num_states, bddfalse);
|
||||||
|
|
@ -415,15 +401,13 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_graph_ptr
|
||||||
sl2(const const_twa_graph_ptr& a, bdd atomic_propositions)
|
sl2(const_twa_graph_ptr a)
|
||||||
{
|
{
|
||||||
return sl2(make_twa_graph(a, twa::prop_set::all()),
|
return sl2_inplace(make_twa_graph(a, twa::prop_set::all()));
|
||||||
atomic_propositions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_graph_ptr
|
||||||
closure(twa_graph_ptr&& a)
|
closure_inplace(twa_graph_ptr a)
|
||||||
{
|
{
|
||||||
a->prop_keep({false, // state_based
|
a->prop_keep({false, // state_based
|
||||||
false, // inherently_weak
|
false, // inherently_weak
|
||||||
|
|
@ -506,33 +490,145 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
twa_graph_ptr
|
twa_graph_ptr
|
||||||
closure(const const_twa_graph_ptr& a)
|
closure(const_twa_graph_ptr a)
|
||||||
{
|
{
|
||||||
return closure(make_twa_graph(a, twa::prop_set::all()));
|
return closure_inplace(make_twa_graph(a, twa::prop_set::all()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The stutter check algorithm to use can be overridden via an
|
namespace
|
||||||
// environment variable.
|
|
||||||
static int default_stutter_check_algorithm()
|
|
||||||
{
|
{
|
||||||
static const char* stutter_check = getenv("SPOT_STUTTER_CHECK");
|
// The stutter check algorithm to use can be overridden via an
|
||||||
if (stutter_check)
|
// environment variable.
|
||||||
{
|
static int default_stutter_check_algorithm()
|
||||||
char* endptr;
|
{
|
||||||
long res = strtol(stutter_check, &endptr, 10);
|
static const char* stutter_check = getenv("SPOT_STUTTER_CHECK");
|
||||||
if (*endptr || res < 0 || res > 9)
|
if (stutter_check)
|
||||||
throw
|
{
|
||||||
std::runtime_error("invalid value for SPOT_STUTTER_CHECK.");
|
char* endptr;
|
||||||
return res;
|
long res = strtol(stutter_check, &endptr, 10);
|
||||||
}
|
if (*endptr || res < 0 || res > 9)
|
||||||
else
|
throw
|
||||||
{
|
std::runtime_error("invalid value for SPOT_STUTTER_CHECK.");
|
||||||
return 8; // The best variant, according to our benchmarks.
|
return res;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 8; // The best variant, according to our benchmarks.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// The own_f and own_nf tell us whether we can modify the aut_f
|
||||||
|
// and aut_nf automata inplace.
|
||||||
|
static bool do_si_check(const_twa_graph_ptr aut_f, bool own_f,
|
||||||
|
const_twa_graph_ptr aut_nf, bool own_nf,
|
||||||
|
int algo)
|
||||||
|
{
|
||||||
|
auto cl = [](const_twa_graph_ptr a, bool own) {
|
||||||
|
if (own)
|
||||||
|
return closure_inplace(std::const_pointer_cast<twa_graph>
|
||||||
|
(std::move(a)));
|
||||||
|
return closure(std::move(a));
|
||||||
|
};
|
||||||
|
auto sl_2 = [](const_twa_graph_ptr a, bool own) {
|
||||||
|
if (own)
|
||||||
|
return sl2_inplace(std::const_pointer_cast<twa_graph>(std::move(a)));
|
||||||
|
return sl2(std::move(a));
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (algo)
|
||||||
|
{
|
||||||
|
case 1: // sl(aut_f) x sl(aut_nf)
|
||||||
|
return product(sl(std::move(aut_f)),
|
||||||
|
sl(std::move(aut_nf)))->is_empty();
|
||||||
|
case 2: // sl(cl(aut_f)) x aut_nf
|
||||||
|
return product(sl(cl(std::move(aut_f), own_f)),
|
||||||
|
std::move(aut_nf))->is_empty();
|
||||||
|
case 3: // (cl(sl(aut_f)) x aut_nf
|
||||||
|
return product(closure_inplace(sl(std::move(aut_f))),
|
||||||
|
std::move(aut_nf))->is_empty();
|
||||||
|
case 4: // sl2(aut_f) x sl2(aut_nf)
|
||||||
|
return product(sl_2(std::move(aut_f), own_f),
|
||||||
|
sl_2(std::move(aut_nf), own_nf))
|
||||||
|
->is_empty();
|
||||||
|
case 5: // sl2(cl(aut_f)) x aut_nf
|
||||||
|
return product(sl2_inplace(cl(std::move(aut_f), own_f)),
|
||||||
|
std::move(aut_nf))->is_empty();
|
||||||
|
case 6: // (cl(sl2(aut_f)) x aut_nf
|
||||||
|
return product(closure_inplace(sl_2(std::move(aut_f), own_f)),
|
||||||
|
std::move(aut_nf))->is_empty();
|
||||||
|
case 7: // on-the-fly sl(aut_f) x sl(aut_nf)
|
||||||
|
return otf_product(make_tgbasl(std::move(aut_f)),
|
||||||
|
make_tgbasl(std::move(aut_nf)))->is_empty();
|
||||||
|
case 8: // cl(aut_f) x cl(aut_nf)
|
||||||
|
return product(cl(std::move(aut_f), own_f),
|
||||||
|
cl(std::move(aut_nf), own_nf))->is_empty();
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("is_stutter_invariant(): "
|
||||||
|
"invalid algorithm number");
|
||||||
|
SPOT_UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_stutter_invariant_aux(twa_graph_ptr aut_f,
|
||||||
|
bool own_f,
|
||||||
|
const_twa_graph_ptr aut_nf = nullptr,
|
||||||
|
int algo = 0)
|
||||||
|
{
|
||||||
|
trival si = aut_f->prop_stutter_invariant();
|
||||||
|
if (si.is_known())
|
||||||
|
return si.is_true();
|
||||||
|
if (aut_nf)
|
||||||
|
{
|
||||||
|
trival si_n = aut_nf->prop_stutter_invariant();
|
||||||
|
if (si_n.is_known())
|
||||||
|
{
|
||||||
|
bool res = si_n.is_true();
|
||||||
|
aut_f->prop_stutter_invariant(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (algo == 0)
|
||||||
|
algo = default_stutter_check_algorithm();
|
||||||
|
|
||||||
|
bool own_nf = false;
|
||||||
|
if (!aut_nf)
|
||||||
|
{
|
||||||
|
twa_graph_ptr tmp = aut_f;
|
||||||
|
if (!is_deterministic(aut_f))
|
||||||
|
{
|
||||||
|
spot::postprocessor p;
|
||||||
|
p.set_type(spot::postprocessor::Generic);
|
||||||
|
p.set_pref(spot::postprocessor::Deterministic);
|
||||||
|
p.set_level(spot::postprocessor::Low);
|
||||||
|
tmp = p.run(aut_f);
|
||||||
|
}
|
||||||
|
aut_nf = dualize(std::move(tmp));
|
||||||
|
own_nf = true;
|
||||||
|
}
|
||||||
|
bool res = do_si_check(aut_f, own_f,
|
||||||
|
std::move(aut_nf), own_nf,
|
||||||
|
algo);
|
||||||
|
aut_f->prop_stutter_invariant(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_stutter_invariant(formula f)
|
is_stutter_invariant(twa_graph_ptr aut_f,
|
||||||
|
const_twa_graph_ptr aut_nf,
|
||||||
|
int algo)
|
||||||
|
{
|
||||||
|
return is_stutter_invariant_aux(aut_f, false, aut_nf, algo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_stutter_invariant(formula f, twa_graph_ptr aut_f)
|
||||||
{
|
{
|
||||||
if (f.is_ltl_formula() && f.is_syntactic_stutter_invariant())
|
if (f.is_ltl_formula() && f.is_syntactic_stutter_invariant())
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -562,55 +658,18 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for an automata-based check.
|
// Prepare for an automata-based check.
|
||||||
translator trans;
|
translator trans(aut_f ? aut_f->get_dict() : make_bdd_dict());
|
||||||
auto aut_f = trans.run(f);
|
bool own_f = false;
|
||||||
auto aut_nf = trans.run(formula::Not(f));
|
if (!aut_f)
|
||||||
bdd aps = atomic_prop_collect_as_bdd(f, aut_f);
|
|
||||||
return is_stutter_invariant(std::move(aut_f), std::move(aut_nf), aps, algo);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
is_stutter_invariant(twa_graph_ptr&& aut_f,
|
|
||||||
twa_graph_ptr&& aut_nf, bdd aps, int algo)
|
|
||||||
{
|
|
||||||
if (algo == 0)
|
|
||||||
algo = default_stutter_check_algorithm();
|
|
||||||
|
|
||||||
switch (algo)
|
|
||||||
{
|
{
|
||||||
case 1: // sl(aut_f) x sl(aut_nf)
|
aut_f = trans.run(f);
|
||||||
return product(sl(std::move(aut_f), aps),
|
own_f = true;
|
||||||
sl(std::move(aut_nf), aps))->is_empty();
|
|
||||||
case 2: // sl(cl(aut_f)) x aut_nf
|
|
||||||
return product(sl(closure(std::move(aut_f)), aps),
|
|
||||||
std::move(aut_nf))->is_empty();
|
|
||||||
case 3: // (cl(sl(aut_f)) x aut_nf
|
|
||||||
return product(closure(sl(std::move(aut_f), aps)),
|
|
||||||
std::move(aut_nf))->is_empty();
|
|
||||||
case 4: // sl2(aut_f) x sl2(aut_nf)
|
|
||||||
return product(sl2(std::move(aut_f), aps),
|
|
||||||
sl2(std::move(aut_nf), aps))->is_empty();
|
|
||||||
case 5: // sl2(cl(aut_f)) x aut_nf
|
|
||||||
return product(sl2(closure(std::move(aut_f)), aps),
|
|
||||||
std::move(aut_nf))->is_empty();
|
|
||||||
case 6: // (cl(sl2(aut_f)) x aut_nf
|
|
||||||
return product(closure(sl2(std::move(aut_f), aps)),
|
|
||||||
std::move(aut_nf))->is_empty();
|
|
||||||
case 7: // on-the-fly sl(aut_f) x sl(aut_nf)
|
|
||||||
return otf_product(make_tgbasl(aut_f, aps),
|
|
||||||
make_tgbasl(aut_nf, aps))->is_empty();
|
|
||||||
case 8: // cl(aut_f) x cl(aut_nf)
|
|
||||||
return product(closure(std::move(aut_f)),
|
|
||||||
closure(std::move(aut_nf)))->is_empty();
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("invalid algorithm number for "
|
|
||||||
"is_stutter_invariant()");
|
|
||||||
SPOT_UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
|
return is_stutter_invariant_aux(aut_f, own_f, trans.run(formula::Not(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
trival
|
trival
|
||||||
check_stutter_invariance(const twa_graph_ptr& aut, formula f,
|
check_stutter_invariance(twa_graph_ptr aut, formula f,
|
||||||
bool do_not_determinize)
|
bool do_not_determinize)
|
||||||
{
|
{
|
||||||
trival is_stut = aut->prop_stutter_invariant();
|
trival is_stut = aut->prop_stutter_invariant();
|
||||||
|
|
@ -619,33 +678,15 @@ namespace spot
|
||||||
|
|
||||||
twa_graph_ptr neg = nullptr;
|
twa_graph_ptr neg = nullptr;
|
||||||
if (f)
|
if (f)
|
||||||
{
|
neg = translator(aut->get_dict()).run(formula::Not(f));
|
||||||
neg = translator(aut->get_dict()).run(formula::Not(f));
|
else if (!is_deterministic(aut) && do_not_determinize)
|
||||||
}
|
return trival::maybe();
|
||||||
else
|
|
||||||
{
|
|
||||||
twa_graph_ptr tmp = aut;
|
|
||||||
if (!is_deterministic(aut))
|
|
||||||
{
|
|
||||||
if (do_not_determinize)
|
|
||||||
return trival::maybe();
|
|
||||||
spot::postprocessor p;
|
|
||||||
p.set_type(spot::postprocessor::Generic);
|
|
||||||
p.set_pref(spot::postprocessor::Deterministic);
|
|
||||||
p.set_level(spot::postprocessor::Low);
|
|
||||||
tmp = p.run(aut);
|
|
||||||
}
|
|
||||||
neg = dualize(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
is_stut = is_stutter_invariant(make_twa_graph(aut, twa::prop_set::all()),
|
return is_stutter_invariant(aut, std::move(neg));
|
||||||
std::move(neg), aut->ap_vars());
|
|
||||||
aut->prop_stutter_invariant(is_stut);
|
|
||||||
return is_stut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<bool>
|
std::vector<bool>
|
||||||
stutter_invariant_states(const const_twa_graph_ptr& pos, formula f,
|
stutter_invariant_states(const_twa_graph_ptr pos, formula f,
|
||||||
bool local)
|
bool local)
|
||||||
{
|
{
|
||||||
if (f.is_syntactic_stutter_invariant()
|
if (f.is_syntactic_stutter_invariant()
|
||||||
|
|
@ -657,7 +698,7 @@ namespace spot
|
||||||
|
|
||||||
// Based on an idea by Joachim Klein.
|
// Based on an idea by Joachim Klein.
|
||||||
std::vector<bool>
|
std::vector<bool>
|
||||||
stutter_invariant_states(const const_twa_graph_ptr& pos,
|
stutter_invariant_states(const_twa_graph_ptr pos,
|
||||||
const_twa_graph_ptr neg,
|
const_twa_graph_ptr neg,
|
||||||
bool local)
|
bool local)
|
||||||
{
|
{
|
||||||
|
|
@ -720,7 +761,7 @@ namespace spot
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
static
|
static
|
||||||
void highlight_vector(const twa_graph_ptr& aut,
|
void highlight_vector(twa_graph_ptr aut,
|
||||||
const std::vector<bool>& v,
|
const std::vector<bool>& v,
|
||||||
unsigned color)
|
unsigned color)
|
||||||
{
|
{
|
||||||
|
|
@ -742,7 +783,7 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
highlight_stutter_invariant_states(const twa_graph_ptr& pos,
|
highlight_stutter_invariant_states(twa_graph_ptr pos,
|
||||||
formula f, unsigned color,
|
formula f, unsigned color,
|
||||||
bool local)
|
bool local)
|
||||||
{
|
{
|
||||||
|
|
@ -750,7 +791,7 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
highlight_stutter_invariant_states(const twa_graph_ptr& pos,
|
highlight_stutter_invariant_states(twa_graph_ptr pos,
|
||||||
const_twa_graph_ptr neg,
|
const_twa_graph_ptr neg,
|
||||||
unsigned color, bool local)
|
unsigned color, bool local)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,79 +21,220 @@
|
||||||
|
|
||||||
#include <spot/twa/twagraph.hh>
|
#include <spot/twa/twagraph.hh>
|
||||||
|
|
||||||
|
/// \defgroup stutter_inv Stutter-invariance checks and related functions
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
/// \ingroup stutter_inv
|
||||||
|
/// \brief Close the automaton by allowing letters to be duplicated.
|
||||||
|
///
|
||||||
|
/// Any letter that enters a state will spawn a copy of this state
|
||||||
|
/// with a self-loop using the same letter. For more details
|
||||||
|
/// about this function, see
|
||||||
|
/** \verbatim
|
||||||
|
@InProceedings{ michaud.15.spin,
|
||||||
|
author = {Thibaud Michaud and Alexandre Duret-Lutz},
|
||||||
|
title = {Practical Stutter-Invariance Checks for
|
||||||
|
{$\omega$}-Regular Languages},
|
||||||
|
booktitle = {Proceedings of the 22th International SPIN
|
||||||
|
Symposium on Model Checking of Software (SPIN'15)},
|
||||||
|
year = 2015,
|
||||||
|
pages = {84--101},
|
||||||
|
series = {Lecture Notes in Computer Science},
|
||||||
|
volume = 9232,
|
||||||
|
publisher = {Springer},
|
||||||
|
month = aug
|
||||||
|
}
|
||||||
|
\endverbatim */
|
||||||
SPOT_API twa_graph_ptr
|
SPOT_API twa_graph_ptr
|
||||||
sl(const twa_graph_ptr&);
|
sl(const_twa_graph_ptr aut);
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// \ingroup stutter_inv
|
||||||
|
/// \brief Close the automaton by allowing letters to be duplicated.
|
||||||
|
///
|
||||||
|
/// For any transition (s,d) labeled by a letter ℓ, we add a state x
|
||||||
|
/// and three transitions (s,x), (x,x), (x,d) all labeled by ℓ.
|
||||||
|
/// For more details about this function, see
|
||||||
|
/** \verbatim
|
||||||
|
@InProceedings{ michaud.15.spin,
|
||||||
|
author = {Thibaud Michaud and Alexandre Duret-Lutz},
|
||||||
|
title = {Practical Stutter-Invariance Checks for
|
||||||
|
{$\omega$}-Regular Languages},
|
||||||
|
booktitle = {Proceedings of the 22th International SPIN
|
||||||
|
Symposium on Model Checking of Software (SPIN'15)},
|
||||||
|
year = 2015,
|
||||||
|
pages = {84--101},
|
||||||
|
series = {Lecture Notes in Computer Science},
|
||||||
|
volume = 9232,
|
||||||
|
publisher = {Springer},
|
||||||
|
month = aug
|
||||||
|
}
|
||||||
|
\endverbatim */
|
||||||
|
///
|
||||||
|
/// The inplace version of the function modifies the input
|
||||||
|
/// automaton.
|
||||||
|
SPOT_API twa_graph_ptr
|
||||||
|
sl2_inplace(twa_graph_ptr aut);
|
||||||
|
|
||||||
SPOT_API twa_graph_ptr
|
SPOT_API twa_graph_ptr
|
||||||
sl(const const_twa_graph_ptr&, bdd);
|
sl2(const_twa_graph_ptr aut);
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
/// @{
|
||||||
|
/// \ingroup stutter_inv
|
||||||
|
/// \brief Close the automaton by allowing duplicate letter removal.
|
||||||
|
///
|
||||||
|
/// This is done by adding shortcuts into the automaton. If (x,y) is
|
||||||
|
/// a transition labeled by B, and (y,z) is a transition labeled by C,
|
||||||
|
/// we add a transition (x,z) labeled by B∧C.
|
||||||
|
///
|
||||||
|
/// For more details about this function, see
|
||||||
|
/** \verbatim
|
||||||
|
@InProceedings{ michaud.15.spin,
|
||||||
|
author = {Thibaud Michaud and Alexandre Duret-Lutz},
|
||||||
|
title = {Practical Stutter-Invariance Checks for
|
||||||
|
{$\omega$}-Regular Languages},
|
||||||
|
booktitle = {Proceedings of the 22th International SPIN
|
||||||
|
Symposium on Model Checking of Software (SPIN'15)},
|
||||||
|
year = 2015,
|
||||||
|
pages = {84--101},
|
||||||
|
series = {Lecture Notes in Computer Science},
|
||||||
|
volume = 9232,
|
||||||
|
publisher = {Springer},
|
||||||
|
month = aug
|
||||||
|
}
|
||||||
|
\endverbatim */
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// The inplace version of the function modifies the input
|
||||||
|
/// automaton.
|
||||||
|
SPOT_API twa_graph_ptr
|
||||||
|
closure_inplace(twa_graph_ptr aut);
|
||||||
|
|
||||||
SPOT_API twa_graph_ptr
|
SPOT_API twa_graph_ptr
|
||||||
sl2(const twa_graph_ptr&);
|
closure(const_twa_graph_ptr aut);
|
||||||
|
/// @}
|
||||||
|
|
||||||
SPOT_API twa_graph_ptr
|
/// \ingroup stutter_inv
|
||||||
sl2(const const_twa_graph_ptr&, bdd);
|
/// \brief Check if a formula is stutter invariant.
|
||||||
|
///
|
||||||
#ifndef SWIG
|
/// It first calls spot::formula::is_syntactic_stutter_invariant()
|
||||||
SPOT_API twa_graph_ptr
|
/// to test for the absence of X, but if some X is found, is an
|
||||||
sl2(twa_graph_ptr&&, bdd = bddfalse);
|
/// automaton-based check is performed to detect reliably (and
|
||||||
#endif
|
/// rather efficiently) whether the language is actually
|
||||||
|
/// stutter-invariant.
|
||||||
SPOT_API twa_graph_ptr
|
///
|
||||||
closure(const const_twa_graph_ptr&);
|
/// If you already have an automaton for f, passing it at a second
|
||||||
|
/// argument will save some time. If you also have an automaton for
|
||||||
#ifndef SWIG
|
/// the negation of f, it is better to use the overload of
|
||||||
SPOT_API twa_graph_ptr
|
/// is_stutter_invariant() that takes two automata.
|
||||||
closure(twa_graph_ptr&&);
|
///
|
||||||
#endif
|
/// The prop_stutter_invariant() property of \a aut_f is set as a
|
||||||
|
/// side-effect.
|
||||||
/// \ingroup ltl_misc
|
///
|
||||||
/// \brief Check if a formula has the stutter invariance property.
|
/// For more details about this function, see
|
||||||
|
/** \verbatim
|
||||||
|
@InProceedings{ michaud.15.spin,
|
||||||
|
author = {Thibaud Michaud and Alexandre Duret-Lutz},
|
||||||
|
title = {Practical Stutter-Invariance Checks for
|
||||||
|
{$\omega$}-Regular Languages},
|
||||||
|
booktitle = {Proceedings of the 22th International SPIN
|
||||||
|
Symposium on Model Checking of Software (SPIN'15)},
|
||||||
|
year = 2015,
|
||||||
|
pages = {84--101},
|
||||||
|
series = {Lecture Notes in Computer Science},
|
||||||
|
volume = 9232,
|
||||||
|
publisher = {Springer},
|
||||||
|
month = aug
|
||||||
|
}
|
||||||
|
\endverbatim */
|
||||||
SPOT_API bool
|
SPOT_API bool
|
||||||
is_stutter_invariant(formula f);
|
is_stutter_invariant(formula f, twa_graph_ptr aut_f = nullptr);
|
||||||
|
|
||||||
|
/// \ingroup stutter_inv
|
||||||
|
/// \brief Check if an automaton has the stutter invariance
|
||||||
|
/// property.
|
||||||
|
///
|
||||||
|
/// The automaton-based check requires the complement automaton to
|
||||||
|
/// be built. If you have one, passing it as the second argument
|
||||||
|
/// will avoid a costly determinization in case \a aut_f is
|
||||||
|
/// non-deterministic.
|
||||||
|
///
|
||||||
|
/// The prop_stutter_invariant() property of \a aut_f is set as a
|
||||||
|
/// side-effect.
|
||||||
|
///
|
||||||
|
/// For more details about this function, see
|
||||||
|
/** \verbatim
|
||||||
|
@InProceedings{ michaud.15.spin,
|
||||||
|
author = {Thibaud Michaud and Alexandre Duret-Lutz},
|
||||||
|
title = {Practical Stutter-Invariance Checks for
|
||||||
|
{$\omega$}-Regular Languages},
|
||||||
|
booktitle = {Proceedings of the 22th International SPIN
|
||||||
|
Symposium on Model Checking of Software (SPIN'15)},
|
||||||
|
year = 2015,
|
||||||
|
pages = {84--101},
|
||||||
|
series = {Lecture Notes in Computer Science},
|
||||||
|
volume = 9232,
|
||||||
|
publisher = {Springer},
|
||||||
|
month = aug
|
||||||
|
}
|
||||||
|
\endverbatim */
|
||||||
SPOT_API bool
|
SPOT_API bool
|
||||||
is_stutter_invariant(twa_graph_ptr&& aut_f,
|
is_stutter_invariant(twa_graph_ptr aut_f,
|
||||||
twa_graph_ptr&& aut_nf, bdd aps,
|
const_twa_graph_ptr aut_nf = nullptr,
|
||||||
int algo = 0);
|
int algo = 0);
|
||||||
|
|
||||||
|
/// \ingroup stutter_inv
|
||||||
/// \brief Check whether \a aut is stutter-invariant
|
/// \brief Check whether \a aut is stutter-invariant
|
||||||
///
|
///
|
||||||
/// This procedure requires the negation of \a aut to
|
/// This procedure requires the negation of \a aut_f to
|
||||||
/// be computed. This is easily done of \a aut is deterministic
|
/// be computed. This is easily done of \a aut_f is deterministic
|
||||||
/// or if a formula represented by \a aut is known. Otherwise
|
/// or if a formula represented by \a aut_f is known. Otherwise
|
||||||
/// \a aut will be complemented by determinization, which can
|
/// \a aut_f will be complemented by determinization, which can
|
||||||
/// be expansive. The determinization can be forbidden using
|
/// be expansive. The determinization can be forbidden using
|
||||||
/// the \a do_not_determinize flag.
|
/// the \a do_not_determinize flag.
|
||||||
///
|
///
|
||||||
/// If no complemented automaton could be constructed, the
|
/// If no complemented automaton could be constructed, the
|
||||||
/// the result will be returned as trival::maybe().
|
/// the result will be returned as trival::maybe().
|
||||||
|
///
|
||||||
|
/// This variant of is_stutter_invariant() is used for the
|
||||||
|
/// --check=stutter option of command-line tools.
|
||||||
SPOT_API trival
|
SPOT_API trival
|
||||||
check_stutter_invariance(const twa_graph_ptr& aut,
|
check_stutter_invariance(twa_graph_ptr aut_f,
|
||||||
formula f = nullptr,
|
formula f = nullptr,
|
||||||
bool do_not_determinize = false);
|
bool do_not_determinize = false);
|
||||||
|
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
|
/// \ingroup stutter_inv
|
||||||
/// \brief Determinate the states that are stutter-invariant in \a pos.
|
/// \brief Determinate the states that are stutter-invariant in \a pos.
|
||||||
///
|
///
|
||||||
|
/// A state is stutter-invariant if the language recognized from
|
||||||
|
/// this state is stutter-invariant, or if the state can only be
|
||||||
|
/// reached by passing though a stutter-invariant state.
|
||||||
|
///
|
||||||
/// The algorithm needs to compute the complement of \a pos. You can
|
/// The algorithm needs to compute the complement of \a pos. You can
|
||||||
/// avoid that costly operation by either supplying the complement
|
/// avoid that costly operation by either supplying the complement
|
||||||
/// automaton, or supplying a formula for the (positive) automaton.
|
/// automaton, or supplying a formula for the (positive) automaton.
|
||||||
SPOT_API std::vector<bool>
|
SPOT_API std::vector<bool>
|
||||||
stutter_invariant_states(const const_twa_graph_ptr& pos,
|
stutter_invariant_states(const_twa_graph_ptr pos,
|
||||||
const_twa_graph_ptr neg = nullptr,
|
const_twa_graph_ptr neg = nullptr,
|
||||||
bool local = false);
|
bool local = false);
|
||||||
|
|
||||||
SPOT_API std::vector<bool>
|
SPOT_API std::vector<bool>
|
||||||
stutter_invariant_states(const const_twa_graph_ptr& pos, formula f_pos,
|
stutter_invariant_states(const_twa_graph_ptr pos, formula f_pos,
|
||||||
bool local = false);
|
bool local = false);
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
|
/// \ingroup stutter_inv
|
||||||
/// \brief Highlight the states of \a pos that are stutter-invariant.
|
/// \brief Highlight the states of \a pos that are stutter-invariant.
|
||||||
///
|
///
|
||||||
|
/// A state is stutter-invariant if the language recognized from
|
||||||
|
/// this state is stutter-invariant, or if the state can only be
|
||||||
|
/// reached by passing though a stutter-invariant state.
|
||||||
|
///
|
||||||
/// The algorithm needs to compute the complement of \a pos. You can
|
/// The algorithm needs to compute the complement of \a pos. You can
|
||||||
/// avoid that costly operation by either supplying the complement
|
/// avoid that costly operation by either supplying the complement
|
||||||
/// automaton, or supplying a formula for the (positive) automaton.
|
/// automaton, or supplying a formula for the (positive) automaton.
|
||||||
|
|
@ -104,11 +245,11 @@ namespace spot
|
||||||
/// stutter_invariant_states(), and using the resulting vector to
|
/// stutter_invariant_states(), and using the resulting vector to
|
||||||
/// setup the "highlight-states" property of the automaton.
|
/// setup the "highlight-states" property of the automaton.
|
||||||
SPOT_API void
|
SPOT_API void
|
||||||
highlight_stutter_invariant_states(const twa_graph_ptr& pos,
|
highlight_stutter_invariant_states(twa_graph_ptr pos,
|
||||||
formula f_pos, unsigned color = 0,
|
formula f_pos, unsigned color = 0,
|
||||||
bool local = false);
|
bool local = false);
|
||||||
SPOT_API void
|
SPOT_API void
|
||||||
highlight_stutter_invariant_states(const twa_graph_ptr& pos,
|
highlight_stutter_invariant_states(twa_graph_ptr pos,
|
||||||
const_twa_graph_ptr neg = nullptr,
|
const_twa_graph_ptr neg = nullptr,
|
||||||
unsigned color = 0,
|
unsigned color = 0,
|
||||||
bool local = false);
|
bool local = false);
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,7 @@ TESTS_ipython = \
|
||||||
python/product.ipynb \
|
python/product.ipynb \
|
||||||
python/randaut.ipynb \
|
python/randaut.ipynb \
|
||||||
python/randltl.ipynb \
|
python/randltl.ipynb \
|
||||||
python/stutter-inv-states.ipynb \
|
python/stutter-inv.ipynb \
|
||||||
python/testingaut.ipynb \
|
python/testingaut.ipynb \
|
||||||
python/word.ipynb
|
python/word.ipynb
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue