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:
|
||||
- *green* components contain an 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)
|
||||
- *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"]
|
||||
}
|
||||
subgraph cluster_1 {
|
||||
color=orange
|
||||
color=grey
|
||||
label=""
|
||||
0 [label="0"]
|
||||
}
|
||||
subgraph cluster_2 {
|
||||
color=orange
|
||||
color=green
|
||||
label=""
|
||||
8 [label="8"]
|
||||
9 [label="9"]
|
||||
|
|
|
|||
|
|
@ -86,12 +86,12 @@ digraph G {
|
|||
6 [label="6"]
|
||||
}
|
||||
subgraph cluster_1 {
|
||||
color=orange
|
||||
color=grey
|
||||
label=""
|
||||
0 [label="0"]
|
||||
}
|
||||
subgraph cluster_2 {
|
||||
color=orange
|
||||
color=green
|
||||
label=""
|
||||
9 [label="9"]
|
||||
10 [label="10"]
|
||||
|
|
@ -148,3 +148,41 @@ digraph G {
|
|||
EOF
|
||||
|
||||
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
|
||||
--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
|
||||
|
||||
run 1 $autfilt -q --is-unambiguous input
|
||||
|
|
|
|||
|
|
@ -478,6 +478,8 @@ namespace spot
|
|||
start();
|
||||
if (si)
|
||||
{
|
||||
si->determine_unknown_acceptance();
|
||||
|
||||
unsigned sccs = si->scc_count();
|
||||
for (unsigned i = 0; i < sccs; ++i)
|
||||
{
|
||||
|
|
@ -493,6 +495,8 @@ namespace spot
|
|||
else if (si->is_rejecting_scc(i))
|
||||
os_ << " color=red\n";
|
||||
else
|
||||
// May only occur if the call to
|
||||
// determine_unknown_acceptance() above is removed.
|
||||
os_ << " color=orange\n";
|
||||
|
||||
if (name_ || opt_show_acc_)
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ namespace spot
|
|||
scc_info* si = given_si;
|
||||
if (!si)
|
||||
si = new scc_info(aut);
|
||||
si->determine_unknown_acceptance();
|
||||
|
||||
F filter(si, std::forward<Args>(args)...);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// -*- coding: utf-8 -*-
|
||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014 Laboratoire de Recherche et
|
||||
// Developpement de l'Epita (LRDE).
|
||||
// Copyright (C) 2009, 2010, 2012, 2013, 2014, 2015 Laboratoire de
|
||||
// Recherche et Developpement de l'Epita (LRDE).
|
||||
//
|
||||
// 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
|
||||
/// exit path leading to an accepting SCC).
|
||||
///
|
||||
/// Additionally, this will try to remove useless acceptance
|
||||
/// conditions. This operation may diminish the number of
|
||||
/// acceptance condition of the automaton (for instance when two
|
||||
/// acceptance conditions are always used together we only keep one)
|
||||
/// but it will never remove all acceptance conditions, even if it
|
||||
/// would be OK to have zero.
|
||||
/// Additionally, for Generalized Büchi acceptance, this will try to
|
||||
/// remove useless acceptance conditions. This operation may
|
||||
/// diminish the number of acceptance condition of the automaton
|
||||
/// (for instance when two acceptance conditions are always used
|
||||
/// together we only keep one) but it will never remove all
|
||||
/// acceptance conditions, even if it would be OK to have zero.
|
||||
///
|
||||
/// Acceptance conditions on transitions going to non-accepting SCC
|
||||
/// are all removed. Acceptance conditions going to an accepting
|
||||
/// SCC and coming from another SCC are only removed if \a
|
||||
/// Acceptance conditions on transitions going to rejecting SCCs are
|
||||
/// all removed. Acceptance conditions going to an accepting SCC
|
||||
/// and coming from another SCC are only removed if \a
|
||||
/// remove_all_useless is set. The default value of \a
|
||||
/// remove_all_useless is \c false because some algorithms (like the
|
||||
/// 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
|
||||
/// 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
|
||||
/// accepting) may destroy this property. Use scc_filter_states()
|
||||
/// instead.
|
||||
|
|
@ -63,10 +63,10 @@ namespace spot
|
|||
|
||||
/// \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.
|
||||
///
|
||||
/// 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
|
||||
/// accepting), then the output TGBA will also have that property.
|
||||
SPOT_API twa_graph_ptr
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <algorithm>
|
||||
#include <queue>
|
||||
#include "twa/bddprint.hh"
|
||||
#include "twaalgos/mask.hh"
|
||||
#include "misc/escape.hh"
|
||||
|
||||
namespace spot
|
||||
|
|
@ -225,16 +226,23 @@ namespace spot
|
|||
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
|
||||
// SCC that is useful.
|
||||
unsigned scccount = scc_count();
|
||||
for (unsigned i = 0; i < scccount; ++i)
|
||||
{
|
||||
|
||||
if (!node_[i].is_rejecting())
|
||||
{
|
||||
node_[i].useful_ = true;
|
||||
continue;
|
||||
}
|
||||
node_[i].useful_ = false;
|
||||
for (auto j: node_[i].succ())
|
||||
if (node_[j.dst].is_useful())
|
||||
{
|
||||
|
|
@ -295,6 +303,29 @@ namespace spot
|
|||
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&
|
||||
dump_scc_info_dot(std::ostream& out,
|
||||
const_twa_graph_ptr aut, scc_info* sccinfo)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ namespace spot
|
|||
}
|
||||
|
||||
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_;
|
||||
const_twa_graph_ptr aut_;
|
||||
|
||||
// Update the useful_ bits. Called automatically.
|
||||
void determine_usefulness();
|
||||
|
||||
const scc_node& node(unsigned scc) const
|
||||
{
|
||||
|
|
@ -198,6 +201,10 @@ namespace spot
|
|||
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
|
||||
{
|
||||
return node(scc).is_useful();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue