twa: add support for prop_complete()

* spot/twa/twa.hh: Add support.  Make two constructors for prop_set in
order to diagnose constructions with 5 arguments.
* spot/parseaut/parseaut.yy: Adjust diagnostics for complete and
deterministic.
* spot/tl/exclusive.cc, spot/twa/twagraph.cc,
spot/twaalgos/alternation.cc, spot/twaalgos/complete.cc,
spot/twaalgos/complete.hh, spot/twaalgos/degen.cc,
spot/twaalgos/determinize.cc, spot/twaalgos/hoa.cc,
spot/twaalgos/isdet.cc, spot/twaalgos/mask.cc,
spot/twaalgos/minimize.cc, spot/twaalgos/product.cc,
spot/twaalgos/remfin.cc, spot/twaalgos/remprop.cc,
spot/twaalgos/sbacc.cc, spot/twaalgos/sccfilter.cc,
spot/twaalgos/simulation.cc, spot/twaalgos/strength.cc,
spot/twaalgos/stutter.cc, spot/twaalgos/totgba.cc,
tests/core/parseaut.test, tests/python/product.ipynb: Adjust.
* NEWS, doc/org/concepts.org, doc/org/hoa.org,
doc/org/tut21.org: Document it.
This commit is contained in:
Alexandre Duret-Lutz 2017-03-16 18:25:07 +01:00
parent 90a8a912e0
commit 0de5f50da9
28 changed files with 296 additions and 106 deletions

3
NEWS
View file

@ -10,6 +10,9 @@ New in spot 2.3.2.dev (not yet released)
- spot::sum() and spot::sum_and() implements the union and the - spot::sum() and spot::sum_and() implements the union and the
intersection of two automatons, respectively. intersection of two automatons, respectively.
- twa objects have a new property: prop_complete(). This obviously
acts as a cache for the is_complete() function.
Bug fixes: Bug fixes:
- In "lenient" mode the parser would fail to recover from - In "lenient" mode the parser would fail to recover from

View file

@ -1056,11 +1056,12 @@ automaton, and that can be queried or set by algorithms:
| flag name | meaning when =true= | | flag name | meaning when =true= |
|----------------------+----------------------------------------------------------------------------------------------| |----------------------+----------------------------------------------------------------------------------------------|
| =state_acc= | automaton should be considered has having state-based acceptance | | =state_acc= | automaton should be considered as having state-based acceptance |
| =inherently_weak= | accepting and rejecting cycles cannot be mixed in the same SCC | | =inherently_weak= | accepting and rejecting cycles cannot be mixed in the same SCC |
| =weak= | transitions of an SCC all belong to the same acceptance sets | | =weak= | transitions of an SCC all belong to the same acceptance sets |
| =very-weak= | weak automaton where all SCCs have size 1 | | =very-weak= | weak automaton where all SCCs have size 1 |
| =terminal= | automaton is weak, accepting SCCs are complete, accepting edges may not go to rejecting SCCs | | =terminal= | automaton is weak, accepting SCCs are complete, accepting edges may not go to rejecting SCCs |
| =complete= | it is always possible to move the automaton forward, using any letter |
| =deterministic= | there is at most one run *recognizing* a word, but not necessarily accepting it | | =deterministic= | there is at most one run *recognizing* a word, but not necessarily accepting it |
| =semi-deterministic= | any nondeterminism occurs before entering an accepting SCC | | =semi-deterministic= | any nondeterminism occurs before entering an accepting SCC |
| =unambiguous= | there is at most one run *accepting* a word (but it might be recognized several time) | | =unambiguous= | there is at most one run *accepting* a word (but it might be recognized several time) |

View file

@ -661,7 +661,7 @@ particular:
| =no-univ-branch= | ignored | no | only if =-Hv= | | | =no-univ-branch= | ignored | no | only if =-Hv= | |
| =univ-branch= | checked | no | checked | | | =univ-branch= | checked | no | checked | |
| =deterministic= | checked | yes | checked | | | =deterministic= | checked | yes | checked | |
| =complete= | checked | no | checked | | | =complete= | checked | yes | checked | |
| =unambiguous= | trusted | yes | as stored if (=-Hv= or not =deterministic=) | can be checked with =--check=unambiguous= | | =unambiguous= | trusted | yes | as stored if (=-Hv= or not =deterministic=) | can be checked with =--check=unambiguous= |
| =semi-deterministic= | trusted | yes | as stored if (=-Hv= or not =deterministic=) | can be checked with =--check=semi-deterministic= | | =semi-deterministic= | trusted | yes | as stored if (=-Hv= or not =deterministic=) | can be checked with =--check=semi-deterministic= |
| =stutter-invariant= | trusted | yes | as stored | can be checked with =--check=stuttering= | | =stutter-invariant= | trusted | yes | as stored | can be checked with =--check=stuttering= |

View file

@ -131,6 +131,7 @@ corresponding BDD variable number, and then use for instance
// would set the deterministic property on its output. In this // would set the deterministic property on its output. In this
// example, the properties that are set come from the "properties:" // example, the properties that are set come from the "properties:"
// line of the input file. // line of the input file.
out << "Complete: " << aut->prop_complete() << '\n';
out << "Deterministic: " << aut->prop_deterministic() << '\n'; out << "Deterministic: " << aut->prop_deterministic() << '\n';
out << "Unambiguous: " << aut->prop_unambiguous() << '\n'; out << "Unambiguous: " << aut->prop_unambiguous() << '\n';
out << "State-Based Acc: " << aut->prop_state_acc() << '\n'; out << "State-Based Acc: " << aut->prop_state_acc() << '\n';
@ -169,6 +170,7 @@ Number of edges: 10
Initial state: 0 Initial state: 0
Atomic propositions: a (=0) b (=1) c (=2) Atomic propositions: a (=0) b (=1) c (=2)
Name: Fa | G(Fb & Fc) Name: Fa | G(Fb & Fc)
Complete: no
Deterministic: no Deterministic: no
Unambiguous: yes Unambiguous: yes
State-Based Acc: maybe State-Based Acc: maybe

View file

@ -146,7 +146,7 @@ extern "C" int strverscmp(const char *s1, const char *s2);
bool aliased_states = false; bool aliased_states = false;
spot::trival deterministic = spot::trival::maybe(); spot::trival deterministic = spot::trival::maybe();
bool complete = false; spot::trival complete = spot::trival::maybe();
bool trans_acc_seen = false; bool trans_acc_seen = false;
std::map<std::string, spot::location> labels; std::map<std::string, spot::location> labels;
@ -471,14 +471,15 @@ header: format-version header-items
error(det.loc, error(det.loc,
"deterministic automata should have at most " "deterministic automata should have at most "
"one initial state"); "one initial state");
res.deterministic = spot::trival::maybe();
} }
res.deterministic = false;
} }
else else
{ {
// Assume the automaton is deterministic until proven // Assume the automaton is deterministic until proven
// wrong, or unless we are building a Kripke structure. // wrong, or unless we are building a Kripke structure.
res.deterministic = !res.opts.want_kripke; if (!res.opts.want_kripke)
res.deterministic = true;
} }
auto complete = res.prop_is_true("complete"); auto complete = res.prop_is_true("complete");
if (ss < 1) if (ss < 1)
@ -495,7 +496,8 @@ header: format-version header-items
{ {
// Assume the automaton is complete until proven // Assume the automaton is complete until proven
// wrong. // wrong.
res.complete = !res.opts.want_kripke; if (!res.opts.want_kripke)
res.complete = true;
} }
// if ap_count == 0, then a Kripke structure could be // if ap_count == 0, then a Kripke structure could be
// declared complete, although that probably doesn't // declared complete, although that probably doesn't
@ -1034,6 +1036,7 @@ body: states
// mention it in the next loop. // mention it in the next loop.
if (s < res.info_states.size()) if (s < res.info_states.size())
res.info_states[s].declared = true; res.info_states[s].declared = true;
res.complete = spot::trival::maybe();
} }
unsigned n = res.info_states.size(); unsigned n = res.info_states.size();
// States with number above res.states have already caused a // States with number above res.states have already caused a
@ -1043,10 +1046,34 @@ body: states
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i)
{ {
auto& p = res.info_states[i]; auto& p = res.info_states[i];
if (p.used && !p.declared) if (!p.declared)
error(p.used_loc, {
"state " + std::to_string(i) + " has no definition"); if (p.used)
error(p.used_loc,
"state " + std::to_string(i) + " has no definition");
if (!p.used && res.complete)
if (auto p = res.prop_is_true("complete"))
{
error(res.states_loc,
"state " + std::to_string(i) +
" has no definition...");
error(p.loc, "... despite 'properties: complete'");
}
res.complete = false;
}
} }
if (res.complete)
if (auto p = res.prop_is_false("complete"))
{
error(@1, "automaton is complete...");
error(p.loc, "... despite 'properties: !complete'");
}
if (res.deterministic)
if (auto p = res.prop_is_false("deterministic"))
{
error(@1, "automaton is deterministic...");
error(p.loc, "... despite 'properties: !deterministic'");
}
} }
state-num: INT state-num: INT
@ -1104,7 +1131,7 @@ checked-state-num: state-num
states: | states state states: | states state
{ {
if ((res.deterministic || res.complete) && !res.opts.want_kripke) if ((res.deterministic.is_true() || res.complete.is_true()))
{ {
bdd available = bddtrue; bdd available = bddtrue;
bool det = true; bool det = true;
@ -1114,7 +1141,7 @@ states: | states state
det = false; det = false;
available -= t.cond; available -= t.cond;
} }
if (res.deterministic && !det) if (res.deterministic.is_true() && !det)
{ {
res.deterministic = false; res.deterministic = false;
if (auto p = res.prop_is_true("deterministic")) if (auto p = res.prop_is_true("deterministic"))
@ -1124,7 +1151,7 @@ states: | states state
"... despite 'properties: deterministic'"); "... despite 'properties: deterministic'");
} }
} }
if (res.complete && available != bddfalse) if (res.complete.is_true() && available != bddfalse)
{ {
res.complete = false; res.complete = false;
if (auto p = res.prop_is_true("complete")) if (auto p = res.prop_is_true("complete"))
@ -1165,7 +1192,7 @@ state: state-name labeled-edges
// Assume the worse. This skips the tests about determinism // Assume the worse. This skips the tests about determinism
// we might perform on the state. // we might perform on the state.
res.deterministic = spot::trival::maybe(); res.deterministic = spot::trival::maybe();
res.complete = false; res.complete = spot::trival::maybe();
} }
@ -1177,6 +1204,11 @@ state-name: "State:" state-label_opt checked-state-num string_opt state-acc_opt
std::ostringstream o; std::ostringstream o;
o << "redeclaration of state " << $3; o << "redeclaration of state " << $3;
error(@1 + @3, o.str()); error(@1 + @3, o.str());
// The additional transitions from extra states might
// led us to believe that the automaton is complete
// while it is not if we ignore them.
if (res.complete.is_true())
res.complete = spot::trival::maybe();
} }
res.info_states[$3].declared = true; res.info_states[$3].declared = true;
res.acc_state = $5; res.acc_state = $5;
@ -1499,7 +1531,7 @@ dstar_header: dstar_sizes
} }
res.acc_style = State_Acc; res.acc_style = State_Acc;
res.deterministic = true; res.deterministic = true;
// res.h->aut->prop_complete(); res.complete = true;
fill_guards(res); fill_guards(res);
res.cur_guard = res.guards.end(); res.cur_guard = res.guards.end();
} }
@ -2230,6 +2262,10 @@ static void fix_initial_state(result_& r)
"a single initial state"); "a single initial state");
return; return;
} }
// Fiddling with initial state may turn an incomplete automaton
// into a complete one.
if (r.complete.is_false())
r.complete = spot::trival::maybe();
// Multiple initial states. We might need to add a fake one, // Multiple initial states. We might need to add a fake one,
// unless one of the actual initial state has no incoming edge. // unless one of the actual initial state has no incoming edge.
auto& aut = r.h->aut; auto& aut = r.h->aut;
@ -2299,7 +2335,9 @@ static void fix_initial_state(result_& r)
static void fix_properties(result_& r) static void fix_properties(result_& r)
{ {
r.aut_or_ks->prop_deterministic(r.deterministic); r.aut_or_ks->prop_deterministic(r.deterministic);
//r.aut_or_ks->prop_complete(r.complete); // std::cerr << "fix det: " << r.deterministic << '\n';
// std::cerr << "fix complete: " << r.complete << '\n';
r.aut_or_ks->prop_complete(r.complete);
if (r.acc_style == State_Acc || if (r.acc_style == State_Acc ||
(r.acc_style == Mixed_Acc && !r.trans_acc_seen)) (r.acc_style == Mixed_Acc && !r.trans_acc_seen))
r.aut_or_ks->prop_state_acc(true); r.aut_or_ks->prop_state_acc(true);

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015, 2016 Laboratoire de Recherche et Développement // Copyright (C) 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.
@ -177,7 +177,7 @@ namespace spot
twa_graph_ptr res = make_twa_graph(aut->get_dict()); twa_graph_ptr res = make_twa_graph(aut->get_dict());
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { true, true, false, true, true }); res->prop_copy(aut, { true, true, false, true, false, true });
res->copy_acceptance_of(aut); res->copy_acceptance_of(aut);
if (simplify_guards) if (simplify_guards)
{ {

View file

@ -1,9 +1,9 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2009, 2011, 2013, 2014, 2015, 2016 Laboratoire de // Copyright (C) 2009, 2011, 2013-2017 Laboratoire de Recherche et
// Recherche et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de // Copyright (C) 2003-2005 Laboratoire d'Informatique de Paris 6
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), // (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
// Université Pierre et Marie Curie. // Pierre et Marie Curie.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -992,6 +992,7 @@ namespace spot
trival::repr_t stutter_invariant:2; // Stutter invariant language. trival::repr_t stutter_invariant:2; // Stutter invariant language.
trival::repr_t very_weak:2; // very-weak, or 1-weak trival::repr_t very_weak:2; // very-weak, or 1-weak
trival::repr_t semi_deterministic:2; // semi-deterministic automaton. trival::repr_t semi_deterministic:2; // semi-deterministic automaton.
trival::repr_t complete:2; // Complete automaton.
}; };
union union
{ {
@ -1267,6 +1268,29 @@ namespace spot
} }
/// \brief Whether the automaton is complete..
///
/// An automaton is complete if for each state the union of the
/// labels of its outgoing transitions is always true.
///
/// Note that this method may return trival::maybe() when it is
/// unknown whether the automaton is complete or not. If you
/// need a true/false answer, prefer the is_complete() function.
///
/// \see prop_complete()
/// \see is_complete()
trival prop_complete() const
{
return is.complete;
}
/// \brief Set the complete property.
///
/// \see is_complete()
void prop_complete(trival val)
{
is.complete = val.val();
}
/// \brief Whether the automaton is deterministic. /// \brief Whether the automaton is deterministic.
/// ///
@ -1404,7 +1428,7 @@ namespace spot
/// ///
/// This can be used for instance as: /// This can be used for instance as:
/// \code /// \code
/// aut->prop_copy(other_aut, {true, false, false, false, true}); /// aut->prop_copy(other_aut, {true, false, false, false, false, true});
/// \endcode /// \endcode
/// This would copy the "state-based acceptance" and /// This would copy the "state-based acceptance" and
/// "stutter invariant" properties from \c other_aut to \c code. /// "stutter invariant" properties from \c other_aut to \c code.
@ -1428,8 +1452,52 @@ namespace spot
bool inherently_weak; ///< preserve inherently weak, weak, & terminal bool inherently_weak; ///< preserve inherently weak, weak, & terminal
bool deterministic; ///< preserve deterministic, semi-det, unambiguous bool deterministic; ///< preserve deterministic, semi-det, unambiguous
bool improve_det; ///< improves deterministic, semi-det, unambiguous bool improve_det; ///< improves deterministic, semi-det, unambiguous
bool complete; ///< preserves completeness
bool stutter_inv; ///< preserve stutter invariance bool stutter_inv; ///< preserve stutter invariance
prop_set()
: state_based(false),
inherently_weak(false),
deterministic(false),
improve_det(false),
complete(false),
stutter_inv(false)
{
}
prop_set(bool state_based,
bool inherently_weak,
bool deterministic,
bool improve_det,
bool complete,
bool stutter_inv)
: state_based(state_based),
inherently_weak(inherently_weak),
deterministic(deterministic),
improve_det(improve_det),
complete(complete),
stutter_inv(stutter_inv)
{
}
#ifndef SWIG
// The "complete" argument was added in Spot 2.4
SPOT_DEPRECATED("prop_set() now takes 6 arguments")
prop_set(bool state_based,
bool inherently_weak,
bool deterministic,
bool improve_det,
bool stutter_inv)
: state_based(state_based),
inherently_weak(inherently_weak),
deterministic(deterministic),
improve_det(improve_det),
complete(false),
stutter_inv(stutter_inv)
{
}
#endif
/// \brief An all-true \c prop_set /// \brief An all-true \c prop_set
/// ///
/// Use that only in algorithms that copy an automaton without /// Use that only in algorithms that copy an automaton without
@ -1439,7 +1507,7 @@ namespace spot
/// properties currently implemented, use an explicit /// properties currently implemented, use an explicit
/// ///
/// \code /// \code
/// {true, true, true, true, true} /// {true, true, true, true, true, true}
/// \endcode /// \endcode
/// ///
/// instead of calling \c all(). This way, the day a new /// instead of calling \c all(). This way, the day a new
@ -1447,7 +1515,7 @@ namespace spot
/// algorithm X, in case that new property is not preserved. /// algorithm X, in case that new property is not preserved.
static prop_set all() static prop_set all()
{ {
return { true, true, true, true, true }; return { true, true, true, true, true, true };
} }
}; };
@ -1492,6 +1560,8 @@ namespace spot
prop_unambiguous(true); prop_unambiguous(true);
} }
} }
if (p.complete)
prop_complete(other->prop_complete());
if (p.stutter_inv) if (p.stutter_inv)
prop_stutter_invariant(other->prop_stutter_invariant()); prop_stutter_invariant(other->prop_stutter_invariant());
} }
@ -1521,6 +1591,8 @@ namespace spot
if (!(p.improve_det && prop_unambiguous().is_true())) if (!(p.improve_det && prop_unambiguous().is_true()))
prop_unambiguous(trival::maybe()); prop_unambiguous(trival::maybe());
} }
if (!p.complete)
prop_complete(trival::maybe());
if (!p.stutter_inv) if (!p.stutter_inv)
prop_stutter_invariant(trival::maybe()); prop_stutter_invariant(trival::maybe());
} }

View file

@ -233,6 +233,14 @@ namespace spot
v = current++; v = current++;
if (current == todo.size()) if (current == todo.size())
return; // No unreachable state. return; // No unreachable state.
// Removing some non-deterministic dead state could make the
// automaton deterministic.
if (prop_deterministic().is_false())
prop_deterministic(trival::maybe());
if (prop_complete().is_false())
prop_complete(trival::maybe());
defrag_states(std::move(todo), current); defrag_states(std::move(todo), current);
} }
@ -393,6 +401,14 @@ namespace spot
useful[s] = -1U; useful[s] = -1U;
if (current == num_states) if (current == num_states)
return; // No useless state. return; // No useless state.
// Removing some non-deterministic dead state could make the
// automaton deterministic. Likewise for non-complete.
if (prop_deterministic().is_false())
prop_deterministic(trival::maybe());
if (prop_complete().is_false())
prop_complete(trival::maybe());
defrag_states(std::move(useful), current); defrag_states(std::move(useful), current);
} }

View file

@ -362,7 +362,7 @@ namespace spot
res->copy_ap_of(aut_); res->copy_ap_of(aut_);
// We preserve deterministic-like properties, and // We preserve deterministic-like properties, and
// stutter-invariance. // stutter-invariance.
res->prop_copy(aut_, {false, false, false, true, true}); res->prop_copy(aut_, {false, false, false, true, true, true});
res->set_generalized_buchi(has_reject_more_ + reject_1_count_); res->set_generalized_buchi(has_reject_more_ + reject_1_count_);
// We for easier computation of outgoing sets, we will // We for easier computation of outgoing sets, we will

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015, 2016 Laboratoire de Recherche et // Copyright (C) 2013-2017 Laboratoire de Recherche et Développement
// Développement de l'Epita. // de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -21,10 +21,12 @@
namespace spot namespace spot
{ {
unsigned complete_here(twa_graph_ptr aut) void complete_here(twa_graph_ptr aut)
{ {
unsigned n = aut->num_states();
unsigned sink = -1U; unsigned sink = -1U;
if (aut->prop_complete().is_true())
return;
unsigned n = aut->num_states();
// UM is a pair (bool, mark). If the Boolean is false, the // UM is a pair (bool, mark). If the Boolean is false, the
// acceptance is always satisfiable. Otherwise, MARK is an // acceptance is always satisfiable. Otherwise, MARK is an
@ -126,24 +128,17 @@ namespace spot
} }
} }
aut->prop_complete(true);
// Get rid of any named property if the automaton changed. // Get rid of any named property if the automaton changed.
if (t < aut->num_edges()) if (t < aut->num_edges())
aut->release_named_properties(); aut->release_named_properties();
else else
assert(t == aut->num_edges()); assert(t == aut->num_edges());
return sink;
} }
twa_graph_ptr complete(const const_twa_ptr& aut) twa_graph_ptr complete(const const_twa_ptr& aut)
{ {
auto res = make_twa_graph(aut, { auto res = make_twa_graph(aut, twa::prop_set::all());
true, // state based
true, // inherently_weak
true, // deterministic
true, // improve det
true, // stutter inv.
});
complete_here(res); complete_here(res);
return res; return res;
} }

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et // Copyright (C) 2013, 2014, 2015, 2017 Laboratoire de Recherche et
// Développement de l'Epita. // Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -25,12 +25,9 @@ namespace spot
{ {
/// \brief Complete a twa_graph in place. /// \brief Complete a twa_graph in place.
/// ///
/// If the TωA has no acceptance set, one will be added. The /// If the TωA has an acceptance condition that is a tautology,
/// returned value is the number of the sink state (it can be a new /// it will be changed into a Büchi automaton.
/// state added for completion, or an existing non-accepting state SPOT_API void complete_here(twa_graph_ptr aut);
/// that has been reused as sink state because it had no outgoing
/// transitions apart from self-loops.)
SPOT_API unsigned complete_here(twa_graph_ptr aut);
/// \brief Clone a twa and complete it. /// \brief Clone a twa and complete it.
/// ///

View file

@ -212,7 +212,7 @@ namespace spot
if (want_sba) if (want_sba)
res->prop_state_acc(true); res->prop_state_acc(true);
// Preserve determinism, weakness, and stutter-invariance // Preserve determinism, weakness, and stutter-invariance
res->prop_copy(a, { false, true, true, true, true }); res->prop_copy(a, { false, true, true, true, true, true });
// Create an order of acceptance conditions. Each entry in this // Create an order of acceptance conditions. Each entry in this
// vector correspond to an acceptance set. Each index can // vector correspond to an acceptance set. Each index can

View file

@ -641,6 +641,7 @@ namespace spot
{ false, // state based { false, // state based
false, // inherently_weak false, // inherently_weak
false, false, // deterministic false, false, // deterministic
true, // complete
true // stutter inv true // stutter inv
}); });

View file

@ -160,8 +160,11 @@ namespace spot
is_colored = colored && (!has_state_acc || nodeadend); is_colored = colored && (!has_state_acc || nodeadend);
// If the automaton declares that it is deterministic or // If the automaton declares that it is deterministic or
// state-based, make sure that it really is. // state-based, make sure that it really is.
assert(deterministic || aut->prop_deterministic() != true); assert(!aut->prop_deterministic().is_known() ||
assert(state_acc || aut->prop_state_acc() != true); deterministic == aut->prop_deterministic().is_true());
assert(!aut->prop_complete().is_known() ||
complete == aut->prop_complete().is_true());
assert(state_acc || !aut->prop_state_acc().is_true());
} }
void number_all_ap(const const_twa_graph_ptr& aut) void number_all_ap(const const_twa_graph_ptr& aut)

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013, 2014, 2015, 2016 Laboratoire de Recherche // Copyright (C) 2012-2017 Laboratoire de Recherche et Développement
// 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.
// //
@ -134,6 +134,9 @@ namespace spot
bool bool
is_complete(const const_twa_graph_ptr& aut) is_complete(const const_twa_graph_ptr& aut)
{ {
trival cp = aut->prop_complete();
if (cp.is_known())
return cp.is_true();
unsigned ns = aut->num_states(); unsigned ns = aut->num_states();
for (unsigned src = 0; src < ns; ++src) for (unsigned src = 0; src < ns; ++src)
{ {
@ -141,11 +144,16 @@ namespace spot
for (auto& t: aut->out(src)) for (auto& t: aut->out(src))
available -= t.cond; available -= t.cond;
if (available != bddfalse) if (available != bddfalse)
return false; {
std::const_pointer_cast<twa_graph>(aut)->prop_complete(false);
return false;
}
} }
// The empty automaton is not complete since it does not have an // The empty automaton is not complete since it does not have an
// initial state. // initial state.
return ns > 0; bool res = ns > 0;
std::const_pointer_cast<twa_graph>(aut)->prop_complete(res);
return res;
} }
bool bool

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015, 2016 Laboratoire de Recherche et Développement // Copyright (C) 2015, 2016, 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.
@ -26,7 +26,7 @@ namespace spot
{ {
auto res = make_twa_graph(in->get_dict()); auto res = make_twa_graph(in->get_dict());
res->copy_ap_of(in); res->copy_ap_of(in);
res->prop_copy(in, { true, true, true, true, false }); res->prop_copy(in, { true, true, false, true, false, false });
unsigned na = in->num_sets(); unsigned na = in->num_sets();
unsigned tr = to_remove.count(); unsigned tr = to_remove.count();
assert(tr <= na); assert(tr <= na);
@ -54,7 +54,7 @@ namespace spot
auto res = make_twa_graph(in->get_dict()); auto res = make_twa_graph(in->get_dict());
res->copy_ap_of(in); res->copy_ap_of(in);
res->prop_copy(in, { true, true, false, true, false }); res->prop_copy(in, { true, true, false, true, false, false });
res->copy_acceptance_of(in); res->copy_acceptance_of(in);
transform_copy(in, res, [&](unsigned src, transform_copy(in, res, [&](unsigned src,
bdd& cond, bdd& cond,
@ -76,7 +76,7 @@ namespace spot
auto res = make_twa_graph(in->get_dict()); auto res = make_twa_graph(in->get_dict());
res->copy_ap_of(in); res->copy_ap_of(in);
res->prop_copy(in, { true, true, false, true, false }); res->prop_copy(in, { true, true, false, true, false, false });
res->copy_acceptance_of(in); res->copy_acceptance_of(in);
transform_accessible(in, res, [&](unsigned src, transform_accessible(in, res, [&](unsigned src,
bdd& cond, bdd& cond,

View file

@ -486,7 +486,7 @@ namespace spot
// final is empty: there is no acceptance condition // final is empty: there is no acceptance condition
build_state_set(det_a, non_final); build_state_set(det_a, non_final);
auto res = minimize_dfa(det_a, final, non_final); auto res = minimize_dfa(det_a, final, non_final);
res->prop_copy(a, { false, false, false, false, true }); res->prop_copy(a, { false, false, false, false, true, true });
res->prop_deterministic(true); res->prop_deterministic(true);
res->prop_weak(true); res->prop_weak(true);
res->prop_state_acc(true); res->prop_state_acc(true);
@ -595,7 +595,7 @@ namespace spot
} }
auto res = minimize_dfa(det_a, final, non_final); auto res = minimize_dfa(det_a, final, non_final);
res->prop_copy(a, { false, false, false, false, true }); res->prop_copy(a, { false, false, false, false, false, true });
res->prop_deterministic(true); res->prop_deterministic(true);
res->prop_weak(true); res->prop_weak(true);
// If the input was terminal, then the output is also terminal. // If the input was terminal, then the output is also terminal.

View file

@ -106,22 +106,21 @@ namespace spot
} }
} }
res->prop_deterministic(left->prop_deterministic() // The product of two non-deterministic automata could be
&& right->prop_deterministic()); // deterministic. likewise for non-complete automata.
res->prop_stutter_invariant(left->prop_stutter_invariant() if (left->prop_deterministic() && right->prop_deterministic())
&& right->prop_stutter_invariant()); res->prop_deterministic(true);
// The product of X!a and Xa, two stutter-sentive formulas, if (left->prop_complete() && right->prop_complete())
// is stutter-invariant. res->prop_complete(true);
//res->prop_stutter_sensitive(left->prop_stutter_sensitive() if (left->prop_stutter_invariant() && right->prop_stutter_invariant())
// && right->prop_stutter_sensitive()); res->prop_stutter_invariant(true);
res->prop_inherently_weak(left->prop_inherently_weak() if (left->prop_inherently_weak() && right->prop_inherently_weak())
&& right->prop_inherently_weak()); res->prop_inherently_weak(true);
res->prop_weak(left->prop_weak() if (left->prop_weak() && right->prop_weak())
&& right->prop_weak()); res->prop_weak(true);
res->prop_terminal(left->prop_terminal() if (left->prop_terminal() && right->prop_terminal())
&& right->prop_terminal()); res->prop_terminal(true);
res->prop_state_acc(left->prop_state_acc() res->prop_state_acc(left->prop_state_acc() && right->prop_state_acc());
&& right->prop_state_acc());
return res; return res;
} }
} }

View file

@ -224,11 +224,12 @@ namespace spot
unsigned nst = aut->num_states(); unsigned nst = aut->num_states();
auto res = make_twa_graph(aut->get_dict()); auto res = make_twa_graph(aut->get_dict());
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { true, false, false, false, true }); res->prop_copy(aut, { true, false, false, false, false, true });
res->new_states(nst); res->new_states(nst);
res->set_buchi(); res->set_buchi();
res->set_init_state(aut->get_init_state_number()); res->set_init_state(aut->get_init_state_number());
trival deterministic = aut->prop_deterministic(); trival deterministic = aut->prop_deterministic();
trival complete = aut->prop_complete();
std::vector<unsigned> state_map(aut->num_states()); std::vector<unsigned> state_map(aut->num_states());
for (unsigned n = 0; n < scc_max; ++n) for (unsigned n = 0; n < scc_max; ++n)
@ -245,11 +246,11 @@ namespace spot
for (auto& t: aut->out(s)) for (auto& t: aut->out(s))
res->new_acc_edge(s, t.dst, t.cond, acc); res->new_acc_edge(s, t.dst, t.cond, acc);
} }
continue;
} }
else else
{ {
deterministic = false; deterministic = false;
complete = trival::maybe();
// The main copy is only accepting for inf_alone // The main copy is only accepting for inf_alone
// and for all Inf sets that have no matching Fin // and for all Inf sets that have no matching Fin
@ -300,8 +301,9 @@ namespace spot
} }
} }
} }
res->purge_dead_states(); res->prop_complete(complete);
res->prop_deterministic(deterministic); res->prop_deterministic(deterministic);
res->purge_dead_states();
return res; return res;
} }
@ -386,10 +388,11 @@ namespace spot
auto res = make_twa_graph(aut, auto res = make_twa_graph(aut,
{ {
true, // state based true, // state based
true, // inherently weak true, // inherently weak
true, true, // determinisitic true, true, // determinisitic
true, // stutter inv. true, // complete
}); true, // stutter inv.
});
scc_info si(res); scc_info si(res);
// We will modify res in place, and the resulting // We will modify res in place, and the resulting
@ -663,7 +666,7 @@ namespace spot
unsigned nst = aut->num_states(); unsigned nst = aut->num_states();
auto res = make_twa_graph(aut->get_dict()); auto res = make_twa_graph(aut->get_dict());
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { true, false, false, false, true }); res->prop_copy(aut, { true, false, false, false, false, true });
res->new_states(nst); res->new_states(nst);
res->set_acceptance(aut->num_sets() + extra_sets, new_code); res->set_acceptance(aut->num_sets() + extra_sets, new_code);
res->set_init_state(aut->get_init_state_number()); res->set_init_state(aut->get_init_state_number());

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015, 2016 Laboratoire de Recherche et Développement de // Copyright (C) 2015-2017 Laboratoire de Recherche et Développement
// 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.
// //
@ -130,7 +130,7 @@ namespace spot
twa_graph_ptr res = make_twa_graph(d); twa_graph_ptr res = make_twa_graph(d);
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { true, true, false, false, false }); res->prop_copy(aut, { true, true, false, false, false, false });
res->copy_acceptance_of(aut); res->copy_acceptance_of(aut);
for (auto ap: props_exist) for (auto ap: props_exist)

View file

@ -57,7 +57,7 @@ namespace spot
auto res = make_twa_graph(old->get_dict()); auto res = make_twa_graph(old->get_dict());
res->copy_ap_of(old); res->copy_ap_of(old);
res->copy_acceptance_of(old); res->copy_acceptance_of(old);
res->prop_copy(old, {false, true, true, true, true}); res->prop_copy(old, {false, true, true, true, true, true});
res->prop_state_acc(true); res->prop_state_acc(true);
typedef std::pair<unsigned, acc_cond::mark_t> pair_t; typedef std::pair<unsigned, acc_cond::mark_t> pair_t;

View file

@ -375,7 +375,7 @@ namespace spot
else else
res = scc_filter_apply<state_filter res = scc_filter_apply<state_filter
<acc_filter_mask<false, true>>>(aut, given_si); <acc_filter_mask<false, true>>>(aut, given_si);
res->prop_copy(aut, { true, true, false, true, true }); res->prop_copy(aut, { true, true, false, true, false, true });
return res; return res;
} }
@ -417,6 +417,7 @@ namespace spot
true, true,
false, false,
true, // determinism improved true, // determinism improved
false,
true, true,
}); });
return res; return res;
@ -451,6 +452,7 @@ namespace spot
{ false, // state-based acceptance is not preserved { false, // state-based acceptance is not preserved
true, true,
false, false, // determinism may not be preserved false, false, // determinism may not be preserved
false,
false, // stutter inv. of suspvars probably altered false, // stutter inv. of suspvars probably altered
}); });
return res; return res;

View file

@ -595,6 +595,7 @@ namespace spot
{ false, // state-based acc forced below { false, // state-based acc forced below
true, // weakness preserved, true, // weakness preserved,
false, true, // determinism improved false, true, // determinism improved
true, // completeness preserved
true, // stutter inv. true, // stutter inv.
}); });
// !unambiguous and !semi-deterministic are not preserved // !unambiguous and !semi-deterministic are not preserved

View file

@ -295,7 +295,7 @@ namespace spot
twa_graph_ptr res = make_twa_graph(aut->get_dict()); twa_graph_ptr res = make_twa_graph(aut->get_dict());
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { true, false, false, true, false }); res->prop_copy(aut, { true, false, false, true, false, false });
if (keep & Strong) if (keep & Strong)
res->copy_acceptance_of(aut); res->copy_acceptance_of(aut);
@ -362,7 +362,7 @@ namespace spot
const_twa_graph_ptr aut = sm.get_aut(); const_twa_graph_ptr aut = sm.get_aut();
twa_graph_ptr res = make_twa_graph(aut->get_dict()); twa_graph_ptr res = make_twa_graph(aut->get_dict());
res->copy_ap_of(aut); res->copy_ap_of(aut);
res->prop_copy(aut, { true, false, false, true, false }); res->prop_copy(aut, { true, false, false, true, false, false });
res->copy_acceptance_of(aut); res->copy_acceptance_of(aut);
auto um = aut->acc().unsat_mark(); auto um = aut->acc().unsat_mark();

View file

@ -400,10 +400,11 @@ namespace spot
} }
} }
if (num_states != a->num_states()) if (num_states != a->num_states())
a->prop_keep({true, // state_based a->prop_keep({true, // state_based
false, // inherently_weak false, // inherently_weak
false, false, // deterministic false, false, // deterministic
false, // stutter inv. true, // complete
false, // stutter inv.
}); });
a->merge_edges(); a->merge_edges();
return a; return a;
@ -423,6 +424,7 @@ namespace spot
a->prop_keep({false, // state_based a->prop_keep({false, // state_based
false, // inherently_weak false, // inherently_weak
false, false, // deterministic false, false, // deterministic
true, // complete
false, // stutter inv. false, // stutter inv.
}); });

View file

@ -146,7 +146,7 @@ namespace spot
auto out = make_twa_graph(in->get_dict()); auto out = make_twa_graph(in->get_dict());
out->copy_ap_of(in); out->copy_ap_of(in);
out->prop_copy(in, {false, false, false, false, true}); out->prop_copy(in, {false, false, false, false, false, true});
out->set_generalized_buchi(p); out->set_generalized_buchi(p);
acc_cond::mark_t outall = out->acc().all_sets(); acc_cond::mark_t outall = out->acc().all_sets();

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2014, 2015, 2016 Laboratoire de Recherche et # Copyright (C) 2014-2017 Laboratoire de Recherche et Développement de
# Développement de l'Epita (LRDE). # l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
# #
@ -367,8 +367,23 @@ State: 1 { 1 }
State: 2 "sink state" { 0 } State: 2 "sink state" { 0 }
2 2 2 2 2 2 2 2
--END-- --END--
HOA: v1.1
name: "GFa"
States: 1
Start: 0
AP: 1 "a"
acc-name: Buchi
Acceptance: 1 Inf(0)
properties: trans-labels explicit-labels trans-acc !complete
properties: !deterministic stutter-invariant
--BODY--
State: 0
[0] 0 {0}
[!0] 0
--END--
EOF EOF
err1="this might cause the following errors"
expecterr input <<EOF expecterr input <<EOF
input:9.5-12.7: not enough transitions for this state input:9.5-12.7: not enough transitions for this state
input:10.7-12.7: these transitions have implicit labels but the automaton is... input:10.7-12.7: these transitions have implicit labels but the automaton is...
@ -377,6 +392,11 @@ input:9.5-12.7: automaton is not complete...
input:7.30-37: ... despite 'properties: complete' input:7.30-37: ... despite 'properties: complete'
input:27.8-10: state label used although the automaton was... input:27.8-10: state label used although the automaton was...
input:25.13-27: ... declared with 'properties: implicit-labels' here input:25.13-27: ... declared with 'properties: implicit-labels' here
input:37.6-9: we can read HOA v1 but this file uses v1.1; $err1
input:46.9-49.6: automaton is complete...
input:44.52-60: ... despite 'properties: !complete'
input:46.9-49.6: automaton is deterministic...
input:45.13-26: ... despite 'properties: !deterministic'
EOF EOF
cat >input<<EOF cat >input<<EOF
@ -1853,6 +1873,15 @@ properties: !inherently-weak weak
--BODY-- --BODY--
State: 0 0 State: 0 0
--END-- --END--
HOA: v1
States: 2
Start: 0
AP: 0
Acceptance: 0 t
properties: complete
--BODY--
State: 0 0
--END--
EOF EOF
expecterr input <<EOF expecterr input <<EOF
@ -1866,6 +1895,8 @@ input:36.36-43: 'properties: terminal' contradicts...
input:36.30-34: ... 'properties: !weak' given here input:36.30-34: ... 'properties: !weak' given here
input:45.30-33: 'properties: weak' contradicts... input:45.30-33: 'properties: weak' contradicts...
input:45.13-28: ... 'properties: !inherently-weak' given here input:45.13-28: ... 'properties: !inherently-weak' given here
input:50.1-9: state 1 has no definition...
input:54.13-20: ... despite 'properties: complete'
EOF EOF
@ -2051,7 +2082,6 @@ State: 0
--END-- --END--
EOF EOF
err1="this might cause the following errors"
expecterr input<<EOF expecterr input<<EOF
input:11.9-11: universal branch used despite previous declaration... input:11.9-11: universal branch used despite previous declaration...
input:7.13-26: ... here input:7.13-26: ... here

View file

@ -1,7 +1,23 @@
{ {
"metadata": { "metadata": {
"name": "", "kernelspec": {
"signature": "sha256:08e64ee189c19ed7e56e5f1c841f51faac25e0bd5e4a6b838856ba8b6f2b5344" "display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.3"
},
"name": ""
}, },
"nbformat": 3, "nbformat": 3,
"nbformat_minor": 0, "nbformat_minor": 0,
@ -367,7 +383,7 @@
"output_type": "pyout", "output_type": "pyout",
"prompt_number": 2, "prompt_number": 2,
"text": [ "text": [
"<IPython.core.display.HTML at 0x7ff45181d390>" "<IPython.core.display.HTML object>"
] ]
} }
], ],
@ -711,7 +727,7 @@
"metadata": {}, "metadata": {},
"output_type": "display_data", "output_type": "display_data",
"text": [ "text": [
"<IPython.core.display.HTML at 0x7ff444140860>" "<IPython.core.display.HTML object>"
] ]
} }
], ],
@ -1066,7 +1082,7 @@
"metadata": {}, "metadata": {},
"output_type": "display_data", "output_type": "display_data",
"text": [ "text": [
"<IPython.core.display.HTML at 0x7ff451801208>" "<IPython.core.display.HTML object>"
] ]
} }
], ],
@ -1487,7 +1503,7 @@
"metadata": {}, "metadata": {},
"output_type": "display_data", "output_type": "display_data",
"text": [ "text": [
"<IPython.core.display.HTML at 0x7ff44409ef98>" "<IPython.core.display.HTML object>"
] ]
}, },
{ {
@ -1664,7 +1680,7 @@
" result.set_state_names(names)\n", " result.set_state_names(names)\n",
" \n", " \n",
" # Loop over all the properties we want to preserve if they hold in both automata\n", " # Loop over all the properties we want to preserve if they hold in both automata\n",
" for p in ('prop_deterministic', 'prop_weak', 'prop_inherently_weak', \n", " for p in ('prop_deterministic', 'prop_complete', 'prop_weak', 'prop_inherently_weak', \n",
" 'prop_terminal', 'prop_stutter_invariant', 'prop_state_acc'):\n", " 'prop_terminal', 'prop_stutter_invariant', 'prop_state_acc'):\n",
" if getattr(left, p)() and getattr(right, p)():\n", " if getattr(left, p)() and getattr(right, p)():\n",
" getattr(result, p)(True)\n", " getattr(result, p)(True)\n",
@ -1991,7 +2007,7 @@
"metadata": {}, "metadata": {},
"output_type": "display_data", "output_type": "display_data",
"text": [ "text": [
"<IPython.core.display.HTML at 0x7ff44408aa58>" "<IPython.core.display.HTML object>"
] ]
}, },
{ {
@ -2026,7 +2042,7 @@
"output_type": "stream", "output_type": "stream",
"stream": "stdout", "stream": "stdout",
"text": [ "text": [
"1000 loops, best of 3: 342 \u00b5s per loop\n" "1000 loops, best of 3: 206 \u00b5s per loop\n"
] ]
} }
], ],
@ -2045,7 +2061,8 @@
"output_type": "stream", "output_type": "stream",
"stream": "stdout", "stream": "stdout",
"text": [ "text": [
"100000 loops, best of 3: 6.44 \u00b5s per loop\n" "The slowest run took 6.27 times longer than the fastest. This could mean that an intermediate result is being cached.\n",
"100000 loops, best of 3: 4.2 \u00b5s per loop\n"
] ]
} }
], ],