scc_info: determine accepting/rejecting-SCCs for any acceptance
* src/twaalgos/sccinfo.cc, src/twaalgos/sccinfo.hh (determine_unknown_acceptance): New function to call explicitly in case one want to know whether the accepting/rejecting status of all SCCs regardless of the acceptance. * src/twaalgos/dotty.cc src/twaalgos/sccfilter.cc, src/twaalgos/sccfilter.hh: Use it. * src/tests/unambig.test, src/tests/sccdot.test: Add more tests. * doc/org/oaut.org: Adjust doc for --dot=s, orange is not output anymore.
This commit is contained in:
parent
07ee3d2dd0
commit
8c32fba8b9
8 changed files with 148 additions and 20 deletions
|
|
@ -676,7 +676,6 @@ they visit some the transitions in the set #0 infinitely often.
|
||||||
The strongly connected components are displayed using the following colors:
|
The strongly connected components are displayed using the following colors:
|
||||||
- *green* components contain an accepting cycle
|
- *green* components contain an accepting cycle
|
||||||
- *red* components contain no accepting cycle
|
- *red* components contain no accepting cycle
|
||||||
- *orange* components may or may not contain an accepting cycle. Such an indecision occur only when using =Fin= acceptance primitive, deciding that would require a better algorithm than what the output routine is using.
|
|
||||||
- *black* components are trivial (i.e., they contain no cycle)
|
- *black* components are trivial (i.e., they contain no cycle)
|
||||||
- *gray* components are useless (i.e., they are non-accepting, and are only followed by non-accepting components)
|
- *gray* components are useless (i.e., they are non-accepting, and are only followed by non-accepting components)
|
||||||
|
|
||||||
|
|
@ -741,12 +740,12 @@ digraph G {
|
||||||
6 [label="6"]
|
6 [label="6"]
|
||||||
}
|
}
|
||||||
subgraph cluster_1 {
|
subgraph cluster_1 {
|
||||||
color=orange
|
color=grey
|
||||||
label=""
|
label=""
|
||||||
0 [label="0"]
|
0 [label="0"]
|
||||||
}
|
}
|
||||||
subgraph cluster_2 {
|
subgraph cluster_2 {
|
||||||
color=orange
|
color=green
|
||||||
label=""
|
label=""
|
||||||
8 [label="8"]
|
8 [label="8"]
|
||||||
9 [label="9"]
|
9 [label="9"]
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,12 @@ digraph G {
|
||||||
6 [label="6"]
|
6 [label="6"]
|
||||||
}
|
}
|
||||||
subgraph cluster_1 {
|
subgraph cluster_1 {
|
||||||
color=orange
|
color=grey
|
||||||
label=""
|
label=""
|
||||||
0 [label="0"]
|
0 [label="0"]
|
||||||
}
|
}
|
||||||
subgraph cluster_2 {
|
subgraph cluster_2 {
|
||||||
color=orange
|
color=green
|
||||||
label=""
|
label=""
|
||||||
9 [label="9"]
|
9 [label="9"]
|
||||||
10 [label="10"]
|
10 [label="10"]
|
||||||
|
|
@ -148,3 +148,41 @@ digraph G {
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
diff out.dot expected
|
diff out.dot expected
|
||||||
|
|
||||||
|
# While we are here, make sure scc_filter remove those grey SCCs.
|
||||||
|
../../bin/autfilt --small -x simul=0 in.hoa -H > out.hoa
|
||||||
|
cat >expected.hoa <<EOF
|
||||||
|
HOA: v1
|
||||||
|
States: 8
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "a" "b"
|
||||||
|
Acceptance: 3 Fin(2) & (Inf(0)&Inf(1))
|
||||||
|
properties: trans-labels explicit-labels trans-acc
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[0&!1] 2
|
||||||
|
[1] 3
|
||||||
|
State: 1
|
||||||
|
[1] 4
|
||||||
|
State: 2
|
||||||
|
[0&1] 0 {0 1}
|
||||||
|
State: 3
|
||||||
|
[1] 1
|
||||||
|
[!1] 3
|
||||||
|
State: 4
|
||||||
|
[!0&1] 4 {0 1}
|
||||||
|
[0&1] 4 {0 2}
|
||||||
|
[t] 5
|
||||||
|
State: 5
|
||||||
|
[0&1] 5 {0 1}
|
||||||
|
[!0&1] 5 {0 2}
|
||||||
|
[t] 6
|
||||||
|
State: 6
|
||||||
|
[!0&1] 6 {0 2}
|
||||||
|
[0&1] 7 {0 1}
|
||||||
|
State: 7
|
||||||
|
[!0&1] 6 {0 1}
|
||||||
|
[0&1] 7 {0 2}
|
||||||
|
--END--
|
||||||
|
EOF
|
||||||
|
diff expected.hoa out.hoa
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,54 @@ State: 1
|
||||||
[0] 1 {0}
|
[0] 1 {0}
|
||||||
[!0] 1
|
[!0] 1
|
||||||
--END--
|
--END--
|
||||||
|
HOA: v1
|
||||||
|
States: 3
|
||||||
|
Start: 0
|
||||||
|
AP: 2 "b" "a"
|
||||||
|
Acceptance: 4 (Fin(1) & Inf(2)) | (Fin(0) & Inf(3))
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0&!1] 1 {1}
|
||||||
|
[0&!1] 0 {1 3}
|
||||||
|
[!0&1] 1 {2}
|
||||||
|
[0&1] 0 {2 3}
|
||||||
|
State: 1
|
||||||
|
[!0&!1] 2 {1}
|
||||||
|
[0&!1] 2 {1 3}
|
||||||
|
[!0&1] 1 {2}
|
||||||
|
[0&1] 1 {2 3}
|
||||||
|
State: 2
|
||||||
|
[!0&!1] 2 {1}
|
||||||
|
[0&!1] 2 {1 3}
|
||||||
|
[!0&1] 2 {1}
|
||||||
|
[0&1] 2 {1 3}
|
||||||
|
[!0] 0 /* extra transition */
|
||||||
|
--END--
|
||||||
|
HOA: v1
|
||||||
|
States: 3
|
||||||
|
Start: 0
|
||||||
|
Start: 2 /* extra initial state */
|
||||||
|
AP: 2 "b" "a"
|
||||||
|
Acceptance: 4 (Fin(1) & Inf(2)) | (Fin(0) & Inf(3))
|
||||||
|
properties: trans-labels explicit-labels trans-acc complete
|
||||||
|
--BODY--
|
||||||
|
State: 0
|
||||||
|
[!0&!1] 1 {1}
|
||||||
|
[0&!1] 0 {1 3}
|
||||||
|
[!0&1] 1 {2}
|
||||||
|
[0&1] 0 {2 3}
|
||||||
|
State: 1
|
||||||
|
[!0&!1] 2 {1}
|
||||||
|
[0&!1] 2 {1 3}
|
||||||
|
[!0&1] 1 {2}
|
||||||
|
[0&1] 1 {2 3}
|
||||||
|
State: 2
|
||||||
|
[!0&!1] 2 {1}
|
||||||
|
[0&!1] 2 {1 3}
|
||||||
|
[!0&1] 2 {1}
|
||||||
|
[0&1] 2 {1 3}
|
||||||
|
--END--
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
run 1 $autfilt -q --is-unambiguous input
|
run 1 $autfilt -q --is-unambiguous input
|
||||||
|
|
|
||||||
|
|
@ -478,6 +478,8 @@ namespace spot
|
||||||
start();
|
start();
|
||||||
if (si)
|
if (si)
|
||||||
{
|
{
|
||||||
|
si->determine_unknown_acceptance();
|
||||||
|
|
||||||
unsigned sccs = si->scc_count();
|
unsigned sccs = si->scc_count();
|
||||||
for (unsigned i = 0; i < sccs; ++i)
|
for (unsigned i = 0; i < sccs; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -493,6 +495,8 @@ namespace spot
|
||||||
else if (si->is_rejecting_scc(i))
|
else if (si->is_rejecting_scc(i))
|
||||||
os_ << " color=red\n";
|
os_ << " color=red\n";
|
||||||
else
|
else
|
||||||
|
// May only occur if the call to
|
||||||
|
// determine_unknown_acceptance() above is removed.
|
||||||
os_ << " color=orange\n";
|
os_ << " color=orange\n";
|
||||||
|
|
||||||
if (name_ || opt_show_acc_)
|
if (name_ || opt_show_acc_)
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,7 @@ namespace spot
|
||||||
scc_info* si = given_si;
|
scc_info* si = given_si;
|
||||||
if (!si)
|
if (!si)
|
||||||
si = new scc_info(aut);
|
si = new scc_info(aut);
|
||||||
|
si->determine_unknown_acceptance();
|
||||||
|
|
||||||
F filter(si, std::forward<Args>(args)...);
|
F filter(si, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- coding: utf-8 -*-
|
// -*- coding: utf-8 -*-
|
||||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche et
|
// Copyright (C) 2009, 2010, 2012, 2013, 2014, 2015 Laboratoire de
|
||||||
// Developpement de l'Epita (LRDE).
|
// Recherche et Developpement de l'Epita (LRDE).
|
||||||
//
|
//
|
||||||
// This file is part of Spot, a model checking library.
|
// This file is part of Spot, a model checking library.
|
||||||
//
|
//
|
||||||
|
|
@ -35,16 +35,16 @@ namespace spot
|
||||||
/// dead SCCs (i.e. SCC that are not accepting, and those with no
|
/// dead SCCs (i.e. SCC that are not accepting, and those with no
|
||||||
/// exit path leading to an accepting SCC).
|
/// exit path leading to an accepting SCC).
|
||||||
///
|
///
|
||||||
/// Additionally, this will try to remove useless acceptance
|
/// Additionally, for Generalized Büchi acceptance, this will try to
|
||||||
/// conditions. This operation may diminish the number of
|
/// remove useless acceptance conditions. This operation may
|
||||||
/// acceptance condition of the automaton (for instance when two
|
/// diminish the number of acceptance condition of the automaton
|
||||||
/// acceptance conditions are always used together we only keep one)
|
/// (for instance when two acceptance conditions are always used
|
||||||
/// but it will never remove all acceptance conditions, even if it
|
/// together we only keep one) but it will never remove all
|
||||||
/// would be OK to have zero.
|
/// acceptance conditions, even if it would be OK to have zero.
|
||||||
///
|
///
|
||||||
/// Acceptance conditions on transitions going to non-accepting SCC
|
/// Acceptance conditions on transitions going to rejecting SCCs are
|
||||||
/// are all removed. Acceptance conditions going to an accepting
|
/// all removed. Acceptance conditions going to an accepting SCC
|
||||||
/// SCC and coming from another SCC are only removed if \a
|
/// and coming from another SCC are only removed if \a
|
||||||
/// remove_all_useless is set. The default value of \a
|
/// remove_all_useless is set. The default value of \a
|
||||||
/// remove_all_useless is \c false because some algorithms (like the
|
/// remove_all_useless is \c false because some algorithms (like the
|
||||||
/// degeneralization) will work better if transitions going to an
|
/// degeneralization) will work better if transitions going to an
|
||||||
|
|
@ -53,7 +53,7 @@ namespace spot
|
||||||
/// If \a given_sm is supplied, the function will use its result
|
/// If \a given_sm is supplied, the function will use its result
|
||||||
/// without computing a map of its own.
|
/// without computing a map of its own.
|
||||||
///
|
///
|
||||||
/// \warning Calling scc_filter on a TGBA that has the SBA property
|
/// \warning Calling scc_filter on a TωA that has the SBA property
|
||||||
/// (i.e., transitions leaving accepting states are all marked as
|
/// (i.e., transitions leaving accepting states are all marked as
|
||||||
/// accepting) may destroy this property. Use scc_filter_states()
|
/// accepting) may destroy this property. Use scc_filter_states()
|
||||||
/// instead.
|
/// instead.
|
||||||
|
|
@ -63,10 +63,10 @@ namespace spot
|
||||||
|
|
||||||
/// \brief Prune unaccepting SCCs.
|
/// \brief Prune unaccepting SCCs.
|
||||||
///
|
///
|
||||||
/// This is an abridged version of scc_filter(), that only remove
|
/// This is an abridged version of scc_filter(), that only removes
|
||||||
/// useless states, without touching at the acceptance conditions.
|
/// useless states, without touching at the acceptance conditions.
|
||||||
///
|
///
|
||||||
/// Especially, if the input TGBA has the SBA property, (i.e.,
|
/// Especially, if the input TωA has the SBA property, (i.e.,
|
||||||
/// transitions leaving accepting states are all marked as
|
/// transitions leaving accepting states are all marked as
|
||||||
/// accepting), then the output TGBA will also have that property.
|
/// accepting), then the output TGBA will also have that property.
|
||||||
SPOT_API twa_graph_ptr
|
SPOT_API twa_graph_ptr
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include "twa/bddprint.hh"
|
#include "twa/bddprint.hh"
|
||||||
|
#include "twaalgos/mask.hh"
|
||||||
#include "misc/escape.hh"
|
#include "misc/escape.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
|
|
@ -225,16 +226,23 @@ namespace spot
|
||||||
root_.front().node.trivial_ = false;
|
root_.front().node.trivial_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
determine_usefulness();
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_info::determine_usefulness()
|
||||||
|
{
|
||||||
// An SCC is useful if it is not rejecting or it has a successor
|
// An SCC is useful if it is not rejecting or it has a successor
|
||||||
// SCC that is useful.
|
// SCC that is useful.
|
||||||
unsigned scccount = scc_count();
|
unsigned scccount = scc_count();
|
||||||
for (unsigned i = 0; i < scccount; ++i)
|
for (unsigned i = 0; i < scccount; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!node_[i].is_rejecting())
|
if (!node_[i].is_rejecting())
|
||||||
{
|
{
|
||||||
node_[i].useful_ = true;
|
node_[i].useful_ = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
node_[i].useful_ = false;
|
||||||
for (auto j: node_[i].succ())
|
for (auto j: node_[i].succ())
|
||||||
if (node_[j.dst].is_useful())
|
if (node_[j.dst].is_useful())
|
||||||
{
|
{
|
||||||
|
|
@ -295,6 +303,29 @@ namespace spot
|
||||||
return support;
|
return support;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void scc_info::determine_unknown_acceptance()
|
||||||
|
{
|
||||||
|
std::vector<bool> k;
|
||||||
|
unsigned n = scc_count();
|
||||||
|
bool changed = false;
|
||||||
|
for (unsigned s = 0; s < n; ++s)
|
||||||
|
if (!is_rejecting_scc(s) && !is_accepting_scc(s))
|
||||||
|
{
|
||||||
|
auto& node = node_[s];
|
||||||
|
if (k.empty())
|
||||||
|
k.resize(aut_->num_states());
|
||||||
|
for (auto i: node.states_)
|
||||||
|
k[i] = true;
|
||||||
|
if (mask_keep_states(aut_, k, node.states_.front())->is_empty())
|
||||||
|
node.rejecting_ = true;
|
||||||
|
else
|
||||||
|
node.accepting_ = true;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
|
determine_usefulness();
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
dump_scc_info_dot(std::ostream& out,
|
dump_scc_info_dot(std::ostream& out,
|
||||||
const_twa_graph_ptr aut, scc_info* sccinfo)
|
const_twa_graph_ptr aut, scc_info* sccinfo)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_node(acc_cond::mark_t acc, bool trivial):
|
scc_node(acc_cond::mark_t acc, bool trivial):
|
||||||
acc_(acc), trivial_(trivial), accepting_(false), useful_(false)
|
acc_(acc), trivial_(trivial), accepting_(false),
|
||||||
|
rejecting_(false), useful_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,6 +113,8 @@ namespace spot
|
||||||
std::vector<scc_node> node_;
|
std::vector<scc_node> node_;
|
||||||
const_twa_graph_ptr aut_;
|
const_twa_graph_ptr aut_;
|
||||||
|
|
||||||
|
// Update the useful_ bits. Called automatically.
|
||||||
|
void determine_usefulness();
|
||||||
|
|
||||||
const scc_node& node(unsigned scc) const
|
const scc_node& node(unsigned scc) const
|
||||||
{
|
{
|
||||||
|
|
@ -198,6 +201,10 @@ namespace spot
|
||||||
return node(scc).is_rejecting();
|
return node(scc).is_rejecting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Study the SCC that are currently reported neither as accepting
|
||||||
|
// nor rejecting because of the presence of Fin sets
|
||||||
|
void determine_unknown_acceptance();
|
||||||
|
|
||||||
bool is_useful_scc(unsigned scc) const
|
bool is_useful_scc(unsigned scc) const
|
||||||
{
|
{
|
||||||
return node(scc).is_useful();
|
return node(scc).is_useful();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue