Keep track of conditions in SCC, and add a more verbose dump.
* src/tgbaalgos/scc.hh (scc_map::scc_of_state, scc_map::cond_set_of, scc_map::acc_set_of, scc_map::states_of): New functions. (scc_map::scc::conds): New attribute. (dump_scc_dot): Take an optional VERBOSE argument. * src/tgbaalgos/scc.cc (scc_map::scc_of_state, scc_map::cond_set_of, scc_map::acc_set_of, scc_map::states_of): Implement these new functions. (dump_scc_dot): Display number of states, conditions and acceptance conditions, with VERBOSE is set. (build_map): Fill the new scc_map::scc::cond field.
This commit is contained in:
parent
cbfdcca1f9
commit
07ead6134e
4 changed files with 112 additions and 21 deletions
16
ChangeLog
16
ChangeLog
|
|
@ -1,3 +1,19 @@
|
||||||
|
2009-05-28 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
||||||
|
|
||||||
|
Keep track of conditions in SCC, and add a more verbose dump.
|
||||||
|
|
||||||
|
* src/tgbaalgos/scc.hh (scc_map::scc_of_state,
|
||||||
|
scc_map::cond_set_of, scc_map::acc_set_of, scc_map::states_of):
|
||||||
|
New functions.
|
||||||
|
(scc_map::scc::conds): New attribute.
|
||||||
|
(dump_scc_dot): Take an optional VERBOSE argument.
|
||||||
|
* src/tgbaalgos/scc.cc (scc_map::scc_of_state,
|
||||||
|
scc_map::cond_set_of, scc_map::acc_set_of, scc_map::states_of):
|
||||||
|
Implement these new functions.
|
||||||
|
(dump_scc_dot): Display number of states, conditions and
|
||||||
|
acceptance conditions, with VERBOSE is set.
|
||||||
|
(build_map): Fill the new scc_map::scc::cond field.
|
||||||
|
|
||||||
2009-05-28 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
2009-05-28 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
||||||
|
|
||||||
* src/tgbaalgos/scc.cc (scc_map::relabel_component): Make sure
|
* src/tgbaalgos/scc.cc (scc_map::relabel_component): Make sure
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include "scc.hh"
|
#include "scc.hh"
|
||||||
#include "tgba/bddprint.hh"
|
#include "tgba/bddprint.hh"
|
||||||
|
|
||||||
|
|
@ -160,8 +161,7 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a successor to look at.
|
// We have a successor to look at.
|
||||||
// Fetch the values (destination state, acceptance conditions
|
// Fetch the values we are interested in...
|
||||||
// of the arc) we are interested in...
|
|
||||||
const state* dest = succ->current_state();
|
const state* dest = succ->current_state();
|
||||||
bdd acc = succ->current_acceptance_conditions();
|
bdd acc = succ->current_acceptance_conditions();
|
||||||
bdd cond = succ->current_condition();
|
bdd cond = succ->current_condition();
|
||||||
|
|
@ -186,7 +186,7 @@ namespace spot
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we reached maximal SCC?
|
// Have we reached a maximal SCC?
|
||||||
if (spi->second < 0)
|
if (spi->second < 0)
|
||||||
{
|
{
|
||||||
int dest = spi->second;
|
int dest = spi->second;
|
||||||
|
|
@ -215,6 +215,8 @@ namespace spot
|
||||||
int threshold = spi->second;
|
int threshold = spi->second;
|
||||||
std::list<const state*> states;
|
std::list<const state*> states;
|
||||||
succ_type succs;
|
succ_type succs;
|
||||||
|
cond_set conds;
|
||||||
|
conds.insert(cond);
|
||||||
while (threshold < root_.front().index)
|
while (threshold < root_.front().index)
|
||||||
{
|
{
|
||||||
assert(!root_.empty());
|
assert(!root_.empty());
|
||||||
|
|
@ -225,23 +227,53 @@ namespace spot
|
||||||
states.splice(states.end(), root_.front().states);
|
states.splice(states.end(), root_.front().states);
|
||||||
succs.insert(root_.front().succ.begin(),
|
succs.insert(root_.front().succ.begin(),
|
||||||
root_.front().succ.end());
|
root_.front().succ.end());
|
||||||
|
conds.insert(arc_cond_.top());
|
||||||
|
conds.insert(root_.front().conds.begin(),
|
||||||
|
root_.front().conds.end());
|
||||||
root_.pop_front();
|
root_.pop_front();
|
||||||
arc_acc_.pop();
|
arc_acc_.pop();
|
||||||
arc_cond_.pop();
|
arc_cond_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we do not always have
|
// Note that we do not always have
|
||||||
// threshold == root_.front().index
|
// threshold == root_.front().index
|
||||||
// after this loop, the SCC whose index is threshold might have
|
// after this loop, the SCC whose index is threshold might have
|
||||||
// been merged with a lower SCC.
|
// been merged with a lower SCC.
|
||||||
|
|
||||||
// Accumulate all acceptance conditions into the merged SCC.
|
// Accumulate all acceptance conditions, states, SCC
|
||||||
|
// successors, and conditions into the merged SCC.
|
||||||
root_.front().acc |= acc;
|
root_.front().acc |= acc;
|
||||||
root_.front().states.splice(root_.front().states.end(), states);
|
root_.front().states.splice(root_.front().states.end(), states);
|
||||||
// Likewise with SCC successors.
|
|
||||||
root_.front().succ.insert(succs.begin(), succs.end());
|
root_.front().succ.insert(succs.begin(), succs.end());
|
||||||
|
root_.front().conds.insert(conds.begin(), conds.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int scc_map::scc_of_state(const state* s) const
|
||||||
|
{
|
||||||
|
hash_type::const_iterator i = h_.find(s);
|
||||||
|
assert(i != h_.end());
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scc_map::cond_set& scc_map::cond_set_of(int n) const
|
||||||
|
{
|
||||||
|
scc_map_type::const_iterator i = scc_map_.find(n);
|
||||||
|
return i->second.conds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd scc_map::acc_set_of(int n) const
|
||||||
|
{
|
||||||
|
scc_map_type::const_iterator i = scc_map_.find(n);
|
||||||
|
return i->second.acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::list<const state*>& scc_map::states_of(int n) const
|
||||||
|
{
|
||||||
|
scc_map_type::const_iterator i = scc_map_.find(n);
|
||||||
|
return i->second.states;
|
||||||
|
}
|
||||||
|
|
||||||
int scc_map::scc_count() const
|
int scc_map::scc_count() const
|
||||||
{
|
{
|
||||||
return -scc_num_;
|
return -scc_num_;
|
||||||
|
|
@ -326,7 +358,7 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
dump_scc_dot(const scc_map& m, std::ostream& out)
|
dump_scc_dot(const scc_map& m, std::ostream& out, bool verbose)
|
||||||
{
|
{
|
||||||
out << "digraph G {\n 0 [label=\"\", style=invis, height=0]" << std::endl;
|
out << "digraph G {\n 0 [label=\"\", style=invis, height=0]" << std::endl;
|
||||||
int start = m.initial();
|
int start = m.initial();
|
||||||
|
|
@ -343,10 +375,33 @@ namespace spot
|
||||||
int state = q.front();
|
int state = q.front();
|
||||||
q.pop();
|
q.pop();
|
||||||
|
|
||||||
if (m.accepting(state))
|
const scc_map::cond_set& cs = m.cond_set_of(state);
|
||||||
std::cout << " " << -state << " [shape=doublecircle]" << std::endl;
|
|
||||||
else
|
std::ostringstream ostr;
|
||||||
std::cout << " " << -state << " [shape=circle]" << std::endl;
|
ostr << -state;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
size_t n = m.states_of(state).size();
|
||||||
|
ostr << " (" << n << " state";
|
||||||
|
if (n > 1)
|
||||||
|
ostr << "s";
|
||||||
|
ostr << ")\\naccs=";
|
||||||
|
bdd_print_accset(ostr, m.get_aut()->get_dict(),
|
||||||
|
m.acc_set_of(state));
|
||||||
|
ostr << "\\nconds=[";
|
||||||
|
for (scc_map::cond_set::const_iterator i = cs.begin();
|
||||||
|
i != cs.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i != cs.begin())
|
||||||
|
ostr << ", ";
|
||||||
|
bdd_print_formula(ostr, m.get_aut()->get_dict(), *i);
|
||||||
|
}
|
||||||
|
ostr << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << " " << -state << " [shape=box,"
|
||||||
|
<< (m.accepting(state) ? "style=bold," : "")
|
||||||
|
<< "label=\"" << ostr.str() << "\"]" << std::endl;
|
||||||
|
|
||||||
const scc_map::succ_type& succ = m.succ(state);
|
const scc_map::succ_type& succ = m.succ(state);
|
||||||
|
|
||||||
|
|
@ -357,9 +412,9 @@ namespace spot
|
||||||
bdd label = it->second;
|
bdd label = it->second;
|
||||||
|
|
||||||
out << " " << -state << " -> " << -dest
|
out << " " << -state << " -> " << -dest
|
||||||
<< " [label=\""
|
<< " [label=\"";
|
||||||
<< bdd_format_formula(m.get_aut()->get_dict(), label)
|
bdd_print_formula(out, m.get_aut()->get_dict(), label);
|
||||||
<< "\"]" << std::endl;
|
out << "\"]" << std::endl;
|
||||||
|
|
||||||
seen_map::const_iterator it = seen.find(dest);
|
seen_map::const_iterator it = seen.find(dest);
|
||||||
if (it != seen.end())
|
if (it != seen.end())
|
||||||
|
|
@ -376,11 +431,11 @@ namespace spot
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
dump_scc_dot(const tgba* a, std::ostream& out)
|
dump_scc_dot(const tgba* a, std::ostream& out, bool verbose)
|
||||||
{
|
{
|
||||||
scc_map m(a);
|
scc_map m(a);
|
||||||
m.build_map();
|
m.build_map();
|
||||||
return dump_scc_dot(m, out);
|
return dump_scc_dot(m, out, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "tgba/tgba.hh"
|
#include "tgba/tgba.hh"
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include "misc/hash.hh"
|
#include "misc/hash.hh"
|
||||||
|
#include "misc/bddlt.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -59,12 +60,18 @@ namespace spot
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::map<int, bdd> succ_type;
|
typedef std::map<int, bdd> succ_type;
|
||||||
|
typedef std::set<bdd, bdd_less_than> cond_set;
|
||||||
|
|
||||||
scc_map(const tgba* aut);
|
scc_map(const tgba* aut);
|
||||||
|
|
||||||
void build_map();
|
void build_map();
|
||||||
void relabel_component(int n);
|
void relabel_component(int n);
|
||||||
|
|
||||||
|
int scc_of_state(const state* s) const;
|
||||||
|
const cond_set& cond_set_of(int n) const;
|
||||||
|
bdd acc_set_of(int n) const;
|
||||||
|
const std::list<const state*>& states_of(int n) const;
|
||||||
|
|
||||||
const tgba* get_aut() const;
|
const tgba* get_aut() const;
|
||||||
|
|
||||||
int scc_count() const;
|
int scc_count() const;
|
||||||
|
|
@ -86,6 +93,8 @@ namespace spot
|
||||||
bdd acc;
|
bdd acc;
|
||||||
/// States of the component.
|
/// States of the component.
|
||||||
std::list<const state*> states;
|
std::list<const state*> states;
|
||||||
|
/// Set of conditions used in the SCC.
|
||||||
|
cond_set conds;
|
||||||
/// Successor SCC.
|
/// Successor SCC.
|
||||||
succ_type succ;
|
succ_type succ;
|
||||||
};
|
};
|
||||||
|
|
@ -113,14 +122,17 @@ namespace spot
|
||||||
// but STATE should not because
|
// but STATE should not because
|
||||||
// it is used as a key in H.
|
// it is used as a key in H.
|
||||||
|
|
||||||
std::map<int, scc> scc_map_; // Map of constructed maximal SCC.
|
typedef std::map<int, scc> scc_map_type;
|
||||||
|
scc_map_type scc_map_; // Map of constructed maximal SCC.
|
||||||
};
|
};
|
||||||
|
|
||||||
scc_stats build_scc_stats(const tgba* a);
|
scc_stats build_scc_stats(const tgba* a);
|
||||||
scc_stats build_scc_stats(const scc_map& m);
|
scc_stats build_scc_stats(const scc_map& m);
|
||||||
|
|
||||||
std::ostream& dump_scc_dot(const tgba* a, std::ostream& out);
|
std::ostream& dump_scc_dot(const tgba* a, std::ostream& out,
|
||||||
std::ostream& dump_scc_dot(const scc_map& m, std::ostream& out);
|
bool verbose = false);
|
||||||
|
std::ostream& dump_scc_dot(const scc_map& m, std::ostream& out,
|
||||||
|
bool verbose = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SPOT_TGBAALGOS_SCC_HH
|
#endif // SPOT_TGBAALGOS_SCC_HH
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Laboratoire
|
// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Laboratoire
|
||||||
// d'Informatique de Paris 6 (LIP6), département Systèmes Répartis
|
// d'Informatique de Paris 6 (LIP6), département Systèmes Répartis
|
||||||
// Coopératifs (SRC), Université Pierre et Marie Curie.
|
// Coopératifs (SRC), Université Pierre et Marie Curie.
|
||||||
//
|
//
|
||||||
|
|
@ -93,7 +93,8 @@ syntax(char* prog)
|
||||||
<< " (requires -e)" << std::endl
|
<< " (requires -e)" << std::endl
|
||||||
<< " -k display statistics on the TGBA instead of dumping it"
|
<< " -k display statistics on the TGBA instead of dumping it"
|
||||||
<< std::endl
|
<< std::endl
|
||||||
<< " -K dump the graph of SCCs in dot"
|
<< " -K dump the graph of SCCs in dot format" << std::endl
|
||||||
|
<< " -KV verbosely dump the graph of SCCs in dot format"
|
||||||
<< std::endl
|
<< std::endl
|
||||||
<< " -L fair-loop approximation (implies -f)" << std::endl
|
<< " -L fair-loop approximation (implies -f)" << std::endl
|
||||||
<< " -m try to reduce accepting runs, in a second pass"
|
<< " -m try to reduce accepting runs, in a second pass"
|
||||||
|
|
@ -332,6 +333,10 @@ main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
output = 10;
|
output = 10;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-KV"))
|
||||||
|
{
|
||||||
|
output = 11;
|
||||||
|
}
|
||||||
else if (!strcmp(argv[formula_index], "-L"))
|
else if (!strcmp(argv[formula_index], "-L"))
|
||||||
{
|
{
|
||||||
fair_loop_approx = true;
|
fair_loop_approx = true;
|
||||||
|
|
@ -742,7 +747,10 @@ main(int argc, char** argv)
|
||||||
build_scc_stats(a).dump(std::cout);
|
build_scc_stats(a).dump(std::cout);
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
dump_scc_dot(a, std::cout);
|
dump_scc_dot(a, std::cout, false);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
dump_scc_dot(a, std::cout, true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(!"unknown output option");
|
assert(!"unknown output option");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue