* src/tgbatest/ltl2tgba.cc: Add some option for the reduction of

automata.
* src/tgbatest/spotlbtt.test, src/tgbatest/Makefile.am: Add some
test for reduction of automata.
* src/tgbaalgos/reductgba_sim_del.cc, src/tgbaalgos/reductgba_sim.cc,
src/tgbaalgos/reductgba_sim.hh: Compute some simulation relation
to reduce a tgba.
* src/tgba/tgbareduc.cc, src/tgba/tgbareduc.hh: A implementation
of tgba for the reduction.
* src/tgbaalgos/Makefile.am, src/tgba/Makefile.am:
Add the reduction of automata.
* src/ltlvisit/syntimpl.cc, src/ltlvisit/basereduc.cc:
Lot of mistake are corrected.
* src/ltlvisit/syntimpl.hh, src/ltlvisit/reducform.cc,
src/ltlvisit/reducform.hh, src/ltltest/reduc.cc: Adjust.
* src/ltltest/equals.cc, src/ltltest/reduccmp.test,
src/ltltest/Makefile.am: Add a test for reduction.
This commit is contained in:
martinez 2004-06-15 16:24:02 +00:00
parent 383f7e170a
commit 8d3606ff07
20 changed files with 3155 additions and 133 deletions

View file

@ -1,4 +1,4 @@
## Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
## et Marie Curie.
##
@ -41,7 +41,8 @@ tgba_HEADERS = \
tgbabddfactory.hh \
tgbaexplicit.hh \
tgbaproduct.hh \
tgbatba.hh
tgbatba.hh \
tgbareduc.hh
noinst_LTLIBRARIES = libtgba.la
libtgba_la_SOURCES = \
@ -57,4 +58,5 @@ libtgba_la_SOURCES = \
tgbabddcoredata.cc \
tgbaexplicit.cc \
tgbaproduct.cc \
tgbatba.cc
tgbatba.cc \
tgbareduc.cc

814
src/tgba/tgbareduc.cc Normal file
View file

@ -0,0 +1,814 @@
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#include "tgbareduc.hh"
#include <sstream>
namespace spot
{
namespace
{
typedef std::pair<const spot::state*, tgba_succ_iterator*> pair_state_iter;
}
tgba_reduc::tgba_reduc(const tgba* a,
const numbered_state_heap_factory* nshf)
: tgba_explicit(a->get_dict()),
tgba_reachable_iterator_breadth_first(a),
h_(nshf->build())
{
dict_->register_all_variables_of(a, this); // useful ??
run();
all_acceptance_conditions_ = a->all_acceptance_conditions();
all_acceptance_conditions_computed_ = true;
seen_ = NULL;
scc_computed_ = false;
}
tgba_reduc::~tgba_reduc()
{
sp_map::iterator i;
for (i = state_predecessor_map_.begin();
i!= state_predecessor_map_.end(); ++i)
{
delete i->second;
}
delete h_;
}
void
tgba_reduc::prune_automata(simulation_relation* rel)
{
// Remember that for each state couple (*i)->second
// simulate (*i)->first.
for (simulation_relation::iterator i = rel->begin();
i != rel->end(); ++i)
{
// All state simulate himself.
if (((*i)->first)->compare((*i)->second) == 0)
continue;
// We check if the two state are co-simulate.
bool recip = false;
for (spot::simulation_relation::iterator j = i;
j != rel->end(); ++j)
if ((((*i)->first)->compare((*j)->second) == 0) &&
(((*j)->first)->compare((*i)->second) == 0))
recip = true;
if (!recip)
this->redirect_transition((*i)->first, (*i)->second);
else
this->merge_state((*i)->first, (*i)->second);
}
this->merge_transitions();
}
void
tgba_reduc::quotient_state(simulation_relation* rel)
{
// Remember that for each state couple (*i)->second
// simulate (*i)->first.
for (simulation_relation::iterator i = rel->begin();
i != rel->end(); ++i)
{
// All state simulate himself.
if (((*i)->first)->compare((*i)->second) == 0)
continue;
// We check if the two state are co-simulate.
bool recip = false;
for (spot::simulation_relation::iterator j = i;
j != rel->end(); ++j)
if ((((*i)->first)->compare((*j)->second) == 0) &&
(((*j)->first)->compare((*i)->second) == 0))
recip = true;
if (recip)
this->merge_state((*i)->first, (*i)->second);
}
this->merge_transitions();
}
void
tgba_reduc::prune_scc()
{
if (!scc_computed_)
this->compute_scc();
this->delete_scc();
}
std::string
tgba_reduc::format_state(const spot::state* s) const
{
std::ostringstream os;
const state_explicit* se = dynamic_cast<const state_explicit*>(s);
assert(se);
sn_map::const_iterator i = state_name_map_.find(se->get_state());
//seen_map::const_iterator j = si_.find(s);
assert(i != state_name_map_.end());
/*
if (j != si_.end()) // SCC have been computed
{
os << ", SCC " << j->second;
return i->second + std::string(os.str());
}
else
*/
return i->second;
}
int
tgba_reduc::get_nb_state()
{
return state_name_map_.size();
}
int
tgba_reduc::get_nb_transition()
{
int nb_transition = 0;
sn_map::iterator i;
for (i = state_name_map_.begin();
i != state_name_map_.end(); ++i)
{
nb_transition += (i->first)->size();
}
return nb_transition;
}
////////////////////////////////////////////
void
tgba_reduc::start()
{
}
void
tgba_reduc::end()
{
}
void
tgba_reduc::process_state(const spot::state* s, int, tgba_succ_iterator* si)
{
spot::state* init = automata_->get_init_state();
if (init->compare(s) == 0)
this->set_init_state(automata_->format_state(s));
delete init;
transition* t;
for (si->first(); !si->done(); si->next())
{
init = si->current_state();
t = this->create_transition(s, init);
this->add_conditions(t, si->current_condition());
this->add_acceptance_conditions(t, si->current_acceptance_conditions());
delete init;
}
}
void
tgba_reduc::process_link(int, int, const tgba_succ_iterator*)
{
}
tgba_explicit::transition*
tgba_reduc::create_transition(const spot::state* source,
const spot::state* dest)
{
const std::string ss = automata_->format_state(source);
const std::string sd = automata_->format_state(dest);
tgba_explicit::state* s
= tgba_explicit::add_state(ss);
tgba_explicit::state* d
= tgba_explicit::add_state(sd);
transition* t = new transition();
t->dest = d;
sp_map::iterator i = state_predecessor_map_.find(d);
if (i == state_predecessor_map_.end())
{
std::list<state*>* pred = new std::list<state*>;
pred->push_back(s);
state_predecessor_map_[d] = pred;
}
else
{
(i->second)->push_back(s);
}
t->condition = bddtrue;
t->acceptance_conditions = bddfalse;
s->push_back(t);
return t;
}
///////////////////////////////////////////////////
void
tgba_reduc::redirect_transition(const spot::state* s,
const spot::state* simul)
{
bool belong = false;
bdd cond_simul;
bdd acc_simul;
std::list<state*> ltmp;
const tgba_explicit::state* s1 = name_state_map_[this->format_state(s)];
const tgba_explicit::state* s2 = name_state_map_[this->format_state(simul)];
sp_map::iterator i = state_predecessor_map_.find(s1);
if (i == state_predecessor_map_.end()) // 0 predecessor
return;
// for all predecessor of s.
for (std::list<state*>::iterator p = (i->second)->begin();
p != (i->second)->end(); ++p)
{
// We check if simul belong to the successor of p,
// as s belong too.
for (tgba_explicit::state::iterator j = (*p)->begin();
j != (*p)->end(); ++j)
if ((*j)->dest == s2) // simul belong to the successor of p.
{
belong = true;
cond_simul = (*j)->condition;
acc_simul = (*j)->acceptance_conditions;
break;
}
// If not, we check for another predecessor of s.
if (!belong)
continue;
// for all successor of p, a predecessor of s and simul.
for (tgba_explicit::state::iterator j = (*p)->begin();
j != (*p)->end(); ++j)
{
// if the transition lead to s.
if (((*j)->dest == s1) &&
// if the label of the transition whose lead to s implies
// this leading to simul.
(((!(*j)->condition | cond_simul) == bddtrue) &&
((!(*j)->acceptance_conditions) | acc_simul) == bddtrue))
{
// We can redirect transition leading to s on simul.
(*j)->dest = const_cast<tgba_explicit::state*>(s2);
// We memorize that we have to remove p
// of the predecessor of s.
ltmp.push_back(*p);
}
}
belong = false;
}
// We remove all the predecessor of s than we have memorized.
std::list<state*>::iterator k;
for (k = ltmp.begin();
k != ltmp.end(); ++k)
this->remove_predecessor_state(i->first, *k);
}
void
tgba_reduc::remove_predecessor_state(const state* s, const state* p)
{
sp_map::iterator i = state_predecessor_map_.find(s);
if (i == state_predecessor_map_.end()) // 0 predecessor
return;
// for all predecessor of s we remove p.
for (std::list<state*>::iterator j = (i->second)->begin();
j != (i->second)->end();)
if (p == *j)
j = (i->second)->erase(j);
else
++j;
}
void
tgba_reduc::remove_state(const spot::state* s)
{
// We suppose than the state is not reachable when call by
// merge_state => NO PREDECESSOR !!
// But it can be have some predecessor in state_predecessor_map_ !!
// So, we remove from it.
ns_map::iterator k = name_state_map_.find(format_state(s));
if (k == name_state_map_.end()) // 0 predecessor
return;
tgba_explicit::state* st = name_state_map_[format_state(s)];
// for all successor q of s, we remove s of the predecessor of q.
for (state::iterator j = st->begin(); j != st->end(); ++j)
this->remove_predecessor_state((*j)->dest, st);
sp_map::iterator i = state_predecessor_map_.find(st);
if (i == state_predecessor_map_.end()) // 0 predecessor
return;
// for all predecessor of s. Zero if call by merge_state.
for (std::list<state*>::iterator p = (i->second)->begin();
p != (i->second)->end(); ++p)
{
// for all transition of p, a predecessor of s.
for (state::iterator j = (*p)->begin();
j != (*p)->end();)
{
if ((*j)->dest == st)
{
// Remove the transition
delete(*j);
j = (*p)->erase(j);
++j;
}
else
++j;
}
}
// DESTROY THE STATE !? USELESS
// it will be destroy when the automaton will be delete
// name_state_map_::iterator = name_state_map_[st];
// const tgba_explicit::state* st = name_state_map_[this->format_state(s)];
}
void
tgba_reduc::merge_state(const spot::state* sim1, const spot::state* sim2)
{
const tgba_explicit::state* s1 = name_state_map_[this->format_state(sim1)];
const tgba_explicit::state* s2 = name_state_map_[this->format_state(sim2)];
const tgba_explicit::state* stmp = s1;
const spot::state* simtmp = sim1;
// if sim1 is the init state, we remove sim2.
spot::state* init = this->get_init_state();
if (sim1->compare(init) == 0)
{
s1 = s2;
s2 = stmp;
sim1 = sim2;
sim2 = simtmp;
}
delete init;
sp_map::iterator i = state_predecessor_map_.find(s1);
if (i == state_predecessor_map_.end()) // 0 predecessor
{
// We can remove s1 safely, without change the language
// of the automaton.
this->remove_state(sim1);
return;
}
// for all predecessor of s1, not the initial state,
// we redirect transition whose lead to s1 to s2.
for (std::list<state*>::iterator p = (i->second)->begin();
p != (i->second)->end(); ++p)
{
// for all successor of p, a predecessor of s1.
for (tgba_explicit::state::iterator j = (*p)->begin();
j != (*p)->end(); ++j)
{
// if the successor if s1.
if ((*j)->dest == s1)
{
// We can redirect transition to s2.
(*j)->dest = const_cast<tgba_explicit::state*>(s2);
}
}
}
// We remove all the predecessor of s1.
(i->second)->clear();
// then we can remove s1 safely, without change the language
// of the automaton.
this->remove_state(sim1);
}
/////////////////////////////////////////
void
tgba_reduc::remove_component(const spot::state* from)
{
std::stack<tgba_succ_iterator*> to_remove;
numbered_state_heap::state_index_p spi = h_->index(from);
assert(spi.first);
assert(*spi.second != -1);
*spi.second = -1;
tgba_succ_iterator* i = this->succ_iter(from);
for (;;)
{
for (i->first(); !i->done(); i->next())
{
spot::state* s = i->current_state();
numbered_state_heap::state_index_p spi = h_->index(s);
if (!spi.first)
continue;
if (*spi.second != -1)
{
*spi.second = -1;
to_remove.push(this->succ_iter(spi.first));
}
}
delete i;
if (to_remove.empty())
break;
i = to_remove.top();
to_remove.pop();
}
}
void
tgba_reduc::compute_scc()
{
std::stack<bdd> arc;
int num = 1;
std::stack<pair_state_iter> todo;
{
spot::state* init = this->get_init_state();
h_->insert(init, 1);
si_[init] = 1;
state_scc_.push(init);
root_.push(1);
arc.push(bddfalse);
tgba_succ_iterator* iter = this->succ_iter(init);
iter->first();
todo.push(pair_state_iter(init, iter));
}
while (!todo.empty())
{
assert(root_.size() == arc.size());
tgba_succ_iterator* succ = todo.top().second;
if (succ->done())
{
const spot::state* curr = todo.top().first;
todo.pop();
numbered_state_heap::state_index_p spi = h_->index(curr);
assert(spi.first);
assert(!root_.empty());
if (root_.top().index == *spi.second)
{
assert(!arc.empty());
arc.pop();
root_.pop();
remove_component(curr);
}
delete succ;
continue;
}
const spot::state* dest = succ->current_state();
bdd acc = succ->current_acceptance_conditions();
succ->next();
numbered_state_heap::state_index_p spi = h_->find(dest);
if (!spi.first)
{
h_->insert(dest, ++num);
si_[dest] = num;
state_scc_.push(dest);
root_.push(num);
arc.push(acc);
tgba_succ_iterator* iter = this->succ_iter(dest);
iter->first();
todo.push(pair_state_iter(dest, iter));
continue;
}
if (*spi.second == -1)
continue;
int threshold = *spi.second;
while (threshold < root_.top().index)
{
assert(!root_.empty());
assert(!arc.empty());
acc |= root_.top().condition;
acc |= arc.top();
root_.pop();
arc.pop();
si_[state_scc_.top()] = threshold;
state_scc_.pop();
}
root_.top().condition |= acc;
}
seen_map::iterator i;
for (i = si_.begin(); i != si_.end(); ++i)
{
state_scc_v_[i->second] = i->first;
}
scc_computed_ = true;
}
void
tgba_reduc::delete_scc()
{
bool change = true;
Sgi::hash_map<int, const spot::state*>::iterator i;
Sgi::hash_map<int, const spot::state*>::iterator itmp;
// we check if there is a terminal SCC we can be remove while
// they have been one removed, because a terminal SCC removed
// can generate a new terminal SCC
while (change)
{
change = false;
for (i = state_scc_v_.begin(); i != state_scc_v_.end();)
{
//std::cout << "Is terminal ? : " << std::endl;
if (is_terminal(i->second))
{
//std::cout << " YES" << std::endl;
change = true;
this->remove_scc(const_cast<spot::state*>(i->second));
itmp = i;
++i;
state_scc_v_.erase(itmp);
}
else
{
++i;
//std::cout << " NO "<< std::endl;
}
}
}
}
bool
tgba_reduc::is_alpha_ball(const spot::state* s, int n)
{
/// FIXME
bool b = false;
seen_map::const_iterator i;
if (n == -1)
{
acc_ == bddfalse;
b = true;
assert(seen_ == NULL);
seen_ = new seen_map();
i = si_.find(s);
assert(i->first != NULL);
n = i->second;
}
seen_map::const_iterator sm = seen_->find(s);
if (sm == seen_->end())
{
seen_->insert(std::pair<const spot::state*, int>(s, 1));
i = si_.find(s);
assert(i->first != 0);
if (n != i->second)
return false;
}
else
{
return true;
}
bool ret = true;
tgba_succ_iterator* j = this->succ_iter(s);
for (j->first(); !j->done(); j->next())
{
acc_ |= j->current_acceptance_conditions();
ret &= this->is_terminal(j->current_state(), n);
}
if (b)
{
delete seen_;
seen_ = NULL;
if (acc_ == this->all_acceptance_conditions())
ret = false;
}
return ret;
}
bool
tgba_reduc::is_terminal(const spot::state* s, int n)
{
// a SCC is terminal if there are no transition
// leaving the SCC AND she doesn't contain all
// the acceptance condition.
// So we can remove it safely without change the
// automaton language.
bool b = false;
seen_map::const_iterator i;
if (n == -1)
{
acc_ == bddfalse;
b = true;
assert(seen_ == NULL);
seen_ = new seen_map();
i = si_.find(s);
assert(i->first != NULL);
n = i->second;
}
seen_map::const_iterator sm = seen_->find(s);
if (sm == seen_->end())
{
// this state is visited for the first time.
seen_->insert(std::pair<const spot::state*, int>(s, 1));
i = si_.find(s);
assert(i->first != 0);
if (n != i->second)
return false;
}
else
{
// This state is already visited.
return true;
}
bool ret = true;
tgba_succ_iterator* j = this->succ_iter(s);
for (j->first(); !j->done(); j->next())
{
acc_ |= j->current_acceptance_conditions();
ret &= this->is_terminal(j->current_state(), n);
}
if (b)
{
delete seen_;
seen_ = NULL;
if (acc_ == this->all_acceptance_conditions())
ret = false;
}
return ret;
}
void
tgba_reduc::remove_scc(spot::state* s)
{
// To remove a scc, we remove all his state.
seen_map::iterator sm = si_.find(s);
sm = si_.find(s);
int n = sm->second;
for (sm == si_.begin(); sm != si_.end(); ++sm)
{
if (sm->second == n)
{
this->remove_state(const_cast<spot::state*>(sm->first));
sm->second = -1;
}
}
}
void
tgba_reduc::remove_scc_depth_first(spot::state* s, int n)
{
if (n == -1)
{
assert(seen_ == NULL);
seen_ = new seen_map();;
}
seen_map::const_iterator sm = seen_->find(s);
if (sm == seen_->end())
seen_->insert(std::pair<const spot::state*, int>(s, 1));
else
return;
tgba_succ_iterator* j = this->succ_iter(s);
for (j->first(); !j->done(); j->next())
{
this->remove_scc_depth_first(j->current_state(), 1);
}
this->remove_state(s);
if (n == -1)
{
delete seen_;
seen_ = NULL;
}
}
//////// JUST FOR DEBUG //////////
void
tgba_reduc::display_rel_sim(simulation_relation* rel,
std::ostream& os)
{
int n = 0;
simulation_relation::iterator i;
for (i = rel->begin(); i != rel->end(); ++i)
{
if (((*i)->first)->compare((*i)->second) == 0)
continue;
n++;
os << "couple " << n
<< std::endl
<< " " << " [label=\""
<< this->format_state((*i)->first) << "\"]"
<< std::endl
<< " " << " [label=\""
<< this->format_state((*i)->second) << "\"]"
<< std::endl
<< std::endl;
}
}
void
tgba_reduc::display_scc(std::ostream& os)
{
while (!root_.empty())
{
os << "index : " << root_.top().index << std::endl;
root_.pop();
}
seen_map::iterator i;
for (i = si_.begin(); i != si_.end(); ++i)
{
os << " [label=\""
<< this->format_state(i->first)
<< "\"]"
<< " scc : "
<< i->second
<< std::endl;
}
os << " Root of each SCC :"
<< std::endl;
Sgi::hash_map<int, const spot::state*>::iterator j;
for (j = state_scc_v_.begin(); j != state_scc_v_.end(); ++j)
{
os << " [label=\""
<< this->format_state(j->second)
<< "\"]"
<< std::endl;
state_scc_.pop();
}
}
}

160
src/tgba/tgbareduc.hh Normal file
View file

@ -0,0 +1,160 @@
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Spot; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
#ifndef SPOT_TGBA_REDUC_HH
# define SPOT_TGBA_REDUC_HH
#include "tgbaexplicit.hh"
#include "tgbaalgos/reachiter.hh"
#include "tgbaalgos/gtec/explscc.hh"
#include "tgbaalgos/gtec/status.hh"
#include <list>
namespace spot
{
typedef Sgi::pair<const spot::state*, const spot::state*> state_couple;
typedef Sgi::vector<state_couple*> simulation_relation;
class tgba_reduc: public tgba_explicit,
public tgba_reachable_iterator_breadth_first
{
public:
tgba_reduc(const tgba* a,
const numbered_state_heap_factory* nshf
= numbered_state_heap_hash_map_factory::instance());
~tgba_reduc();
/// Reduce the automata using a relation simulation
/// Do not call this method with a delayed simulation relation.
void prune_automata(simulation_relation* rel);
/// Build the quotient automata. Call this method
/// when use to a delayed simulation relation.
void quotient_state(simulation_relation* rel);
/// Remove all state which not lead to an accepting cycle.
void prune_scc();
/// Compute the maximal SCC of the automata.
void compute_scc();
/// Add the SCC index to the display of the state \a state.
virtual std::string format_state(const spot::state* state) const;
/// Obsolete.
int get_nb_state();
int get_nb_transition();
// Just for Debug !!
void display_rel_sim(simulation_relation* rel, std::ostream& os);
void display_scc(std::ostream& os);
protected:
bool scc_computed_;
scc_stack root_;
numbered_state_heap* h_;
std::stack<const spot::state*> state_scc_;
Sgi::hash_map<int, const spot::state*> state_scc_v_;
typedef Sgi::hash_map<const tgba_explicit::state*,
std::list<state*>*,
ptr_hash<tgba_explicit::state> > sp_map;
sp_map state_predecessor_map_;
typedef Sgi::hash_map<const spot::state*, int,
state_ptr_hash, state_ptr_equal> seen_map;
seen_map si_;
seen_map* seen_;
bdd acc_;
// Interface of tgba_reachable_iterator_breadth_first
void start();
void end();
void process_state(const spot::state* s, int n, tgba_succ_iterator* si);
void process_link(int in, int out, const tgba_succ_iterator* si);
/// Create a transition using two state of a TGBA.
transition* create_transition(const spot::state* source,
const spot::state* dest);
/// Remove all the transition from the state q, predecessor
/// of both \a s and \a simul, which can be removed.
void redirect_transition(const spot::state* s,
const spot::state* simul);
/// Remove p of the predecessor of s.
void remove_predecessor_state(const state* s, const state* p);
/// Remove all the transition leading to s.
/// s is then unreachable and can be consider as remove.
void remove_state(const spot::state* s);
/// Redirect all transition leading to s1 to s2.
/// Note that we can do the reverse because
/// s1 and s2 belong to a co-simulate relation.
void merge_state(const spot::state* s1,
const spot::state* s2);
/// Remove all the scc which are terminal and doesn't
/// contains all the acceptance conditions.
void delete_scc();
/// Return true if the scc which contains \a s
/// is an fixed-formula alpha-ball.
/// this is explain in
/// \verbatim
/// @InProceedings{ etessami.00.concur,
/// author = {Kousha Etessami and Gerard J. Holzmann},
/// title = {Optimizing {B\"u}chi Automata},
/// booktitle = {Proceedings of the 11th International Conference on
/// Concurrency Theory (Concur'2000)},
/// pages = {153--167},
/// year = {2000},
/// editor = {C. Palamidessi},
/// volume = {1877},
/// series = {Lecture Notes in Computer Science},
/// publisher = {Springer-Verlag}
/// }
/// \endverbatim
bool is_alpha_ball(const spot::state* s,
int n = -1);
// Return true if we can't reach a state with
// an other value of scc.
bool is_terminal(const spot::state* s,
int n = -1);
/// For compute_scc.
void remove_component(const spot::state* from);
/// Remove all the state which belong to the same scc that s.
void remove_scc(spot::state* s);
/// Same as remove_scc but more efficient.
void remove_scc_depth_first(spot::state* s, int n = -1);
};
}
#endif // SPOT_TGBA_REDUC_HH