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:
Alexandre Duret-Lutz 2015-05-13 23:16:26 +02:00
parent 07ee3d2dd0
commit 8c32fba8b9
8 changed files with 148 additions and 20 deletions

View file

@ -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"]

View file

@ -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

View file

@ -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

View file

@ -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_)

View file

@ -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)...);

View file

@ -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

View file

@ -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)

View file

@ -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();