* 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:
parent
383f7e170a
commit
8d3606ff07
20 changed files with 3155 additions and 133 deletions
655
src/tgbaalgos/reductgba_sim.cc
Normal file
655
src/tgbaalgos/reductgba_sim.cc
Normal file
|
|
@ -0,0 +1,655 @@
|
|||
// 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 "reductgba_sim.hh"
|
||||
#include "tgba/bddprint.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// spoiler_node
|
||||
|
||||
spoiler_node::spoiler_node(const state* d_node,
|
||||
const state* s_node,
|
||||
int num)
|
||||
{
|
||||
num_ = num;
|
||||
sc_ = new state_couple(d_node, s_node);
|
||||
//lnode_succ = new Sgi::vector<spoiler_node*>;
|
||||
lnode_succ = new sn_v;
|
||||
lnode_pred = new sn_v;
|
||||
this->not_win = false;
|
||||
}
|
||||
|
||||
spoiler_node::~spoiler_node()
|
||||
{
|
||||
lnode_succ->clear();
|
||||
lnode_pred->clear();
|
||||
delete lnode_succ;
|
||||
delete lnode_pred;
|
||||
delete sc_;
|
||||
}
|
||||
|
||||
void
|
||||
spoiler_node::add_succ(spoiler_node* n)
|
||||
{
|
||||
lnode_succ->push_back(n);
|
||||
}
|
||||
|
||||
void
|
||||
spoiler_node::del_succ(spoiler_node* n)
|
||||
{
|
||||
//std::cout << "del_succ : begin" << std::endl;
|
||||
for (sn_v::iterator i = lnode_succ->begin();
|
||||
i != lnode_succ->end();)
|
||||
{
|
||||
if (*i == n)
|
||||
{
|
||||
//std::cout << "erase" << std::endl;
|
||||
i = lnode_succ->erase(i);
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
//std::cout << "del_succ : end" << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
spoiler_node::add_pred(spoiler_node* n)
|
||||
{
|
||||
lnode_pred->push_back(n);
|
||||
}
|
||||
|
||||
void
|
||||
spoiler_node::del_pred()
|
||||
{
|
||||
for (sn_v::iterator i = lnode_pred->begin();
|
||||
i != lnode_pred->end(); ++i)
|
||||
(*i)->del_succ(this);
|
||||
}
|
||||
|
||||
bool
|
||||
spoiler_node::set_win()
|
||||
{
|
||||
bool change = not_win;
|
||||
for (Sgi::vector<spoiler_node*>::iterator i = lnode_succ->begin();
|
||||
i != lnode_succ->end(); ++i)
|
||||
{
|
||||
not_win |= (*i)->not_win;
|
||||
}
|
||||
return (change != not_win);
|
||||
}
|
||||
|
||||
std::string
|
||||
spoiler_node::to_string(const tgba* a)
|
||||
{
|
||||
std::ostringstream os;
|
||||
// print the node.
|
||||
os << num_
|
||||
<< " [shape=box, label=\"("
|
||||
<< a->format_state(sc_->first)
|
||||
<< ", "
|
||||
<< a->format_state(sc_->second)
|
||||
<< ")\"]"
|
||||
<< std::endl;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
spoiler_node::succ_to_string()
|
||||
{
|
||||
std::ostringstream os;
|
||||
sn_v::iterator i;
|
||||
for (i = lnode_succ->begin(); i != lnode_succ->end(); ++i)
|
||||
{
|
||||
os << num_ << " -> " << (*i)->num_ << std::endl;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
int
|
||||
spoiler_node::get_nb_succ()
|
||||
{
|
||||
return lnode_succ->size();
|
||||
}
|
||||
|
||||
const state*
|
||||
spoiler_node::get_spoiler_node()
|
||||
{
|
||||
return sc_->first;
|
||||
}
|
||||
|
||||
const state*
|
||||
spoiler_node::get_duplicator_node()
|
||||
{
|
||||
return sc_->second;
|
||||
}
|
||||
|
||||
state_couple*
|
||||
spoiler_node::get_pair()
|
||||
{
|
||||
return sc_;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// duplicator_node
|
||||
|
||||
duplicator_node::duplicator_node(const state* d_node,
|
||||
const state* s_node,
|
||||
bdd l,
|
||||
bdd a,
|
||||
int num)
|
||||
: spoiler_node(d_node, s_node, num),
|
||||
label_(l),
|
||||
acc_(a)
|
||||
{
|
||||
}
|
||||
|
||||
duplicator_node::~duplicator_node()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
duplicator_node::set_win()
|
||||
{
|
||||
bool change = not_win;
|
||||
|
||||
if (!this->get_nb_succ())
|
||||
not_win = true;
|
||||
else
|
||||
{
|
||||
not_win = true;
|
||||
for (Sgi::vector<spoiler_node*>::iterator i = lnode_succ->begin();
|
||||
i != lnode_succ->end(); ++i)
|
||||
{
|
||||
not_win &= (*i)->not_win;
|
||||
}
|
||||
}
|
||||
return (change != not_win);
|
||||
}
|
||||
|
||||
std::string
|
||||
duplicator_node::to_string(const tgba* a)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
// print the node.
|
||||
os << num_
|
||||
<< " [shape=box, label=\"("
|
||||
<< a->format_state(sc_->first)
|
||||
<< ", "
|
||||
<< a->format_state(sc_->second)
|
||||
<< ", ";
|
||||
bdd_print_acc(os, a->get_dict(), acc_);
|
||||
os << ")\"]"
|
||||
<< std::endl;
|
||||
|
||||
return os.str();
|
||||
}
|
||||
|
||||
bool
|
||||
duplicator_node::match(bdd l, bdd a)
|
||||
{
|
||||
return ((l == label_) && (a == acc_));
|
||||
}
|
||||
|
||||
bool
|
||||
duplicator_node::implies(bdd l, bdd a)
|
||||
{
|
||||
// if (a | !b) == true then (a => b).
|
||||
return (((l | !label_) == bddtrue) &&
|
||||
((a | !acc_) == bddtrue));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// parity_game_graph
|
||||
|
||||
void
|
||||
parity_game_graph::start()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
parity_game_graph::end()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
parity_game_graph::process_state(const state* s,
|
||||
int ,
|
||||
tgba_succ_iterator*)
|
||||
{
|
||||
tgba_state_.push_back(s);
|
||||
}
|
||||
|
||||
void
|
||||
parity_game_graph::process_link(int ,
|
||||
int ,
|
||||
const tgba_succ_iterator*)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
parity_game_graph::print(std::ostream& os)
|
||||
{
|
||||
Sgi::vector<spoiler_node*>::iterator i1;
|
||||
Sgi::vector<duplicator_node*>::iterator i2;
|
||||
|
||||
int n = 0;
|
||||
|
||||
os << "digraph G {" << std::endl;
|
||||
|
||||
os << "{" << std::endl
|
||||
<< "rank = same;" << std::endl
|
||||
<< "node [color=red];" << std::endl;
|
||||
for (i1 = spoiler_vertice_.begin();
|
||||
i1 != spoiler_vertice_.end(); ++i1)
|
||||
{
|
||||
os << (*i1)->to_string(automata_);
|
||||
n++;
|
||||
if (n > 20)
|
||||
{
|
||||
n = 0;
|
||||
os << "}" << std::endl << std::endl
|
||||
<< "{" << std::endl
|
||||
<< "rank = same" << std::endl
|
||||
<< "node [color=red];" << std::endl;
|
||||
}
|
||||
}
|
||||
os << "}" << std::endl;
|
||||
|
||||
n = 0;
|
||||
os << "{" << std::endl
|
||||
<< "rank = same;" << std::endl
|
||||
<< "node [color=green];" << std::endl;
|
||||
for (i2 = duplicator_vertice_.begin();
|
||||
i2 != duplicator_vertice_.end(); ++i2)
|
||||
{
|
||||
os << (*i2)->to_string(automata_);
|
||||
n++;
|
||||
if (n > 20)
|
||||
{
|
||||
n = 0;
|
||||
os << "}" << std::endl << std::endl
|
||||
<< "{" << std::endl
|
||||
<< "rank = same" << std::endl
|
||||
<< "node [color=green];" << std::endl;
|
||||
}
|
||||
}
|
||||
os << "}" << std::endl << std::endl;
|
||||
|
||||
os << "edge [color=red];" << std::endl;
|
||||
for (i1 = spoiler_vertice_.begin();
|
||||
i1 != spoiler_vertice_.end(); ++i1)
|
||||
{
|
||||
os << (*i1)->succ_to_string();
|
||||
}
|
||||
|
||||
os << std::endl
|
||||
<< "edge [color=green];" << std::endl;
|
||||
for (i2 = duplicator_vertice_.begin();
|
||||
i2 != duplicator_vertice_.end(); ++i2)
|
||||
{
|
||||
os << (*i2)->succ_to_string();
|
||||
}
|
||||
|
||||
os << "}" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
parity_game_graph::~parity_game_graph()
|
||||
{
|
||||
Sgi::vector<spoiler_node*>::iterator i1;
|
||||
Sgi::vector<duplicator_node*>::iterator i2;
|
||||
|
||||
for (i1 = spoiler_vertice_.begin();
|
||||
i1 != spoiler_vertice_.end(); ++i1)
|
||||
{
|
||||
delete *i1;
|
||||
}
|
||||
|
||||
for (i2 = duplicator_vertice_.begin();
|
||||
i2 != duplicator_vertice_.end(); ++i2)
|
||||
{
|
||||
delete *i2;
|
||||
}
|
||||
|
||||
spoiler_vertice_.clear();
|
||||
duplicator_vertice_.clear();
|
||||
}
|
||||
|
||||
parity_game_graph::parity_game_graph(const tgba* a)
|
||||
: tgba_reachable_iterator_breadth_first(a)
|
||||
{
|
||||
this->run();
|
||||
nb_node_parity_game = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// parity_game_graph_direct
|
||||
|
||||
void
|
||||
parity_game_graph_direct::build_couple()
|
||||
{
|
||||
tgba_succ_iterator* si = NULL;
|
||||
typedef Sgi::pair<bdd, bdd> couple_bdd;
|
||||
couple_bdd *p = NULL;
|
||||
Sgi::vector<couple_bdd*>* trans = NULL;
|
||||
bool exist = false;
|
||||
spot::state* s = NULL;
|
||||
|
||||
for (Sgi::vector<const state*>::iterator i = tgba_state_.begin();
|
||||
i != tgba_state_.end(); ++i)
|
||||
{
|
||||
|
||||
// spoiler node are all state couple (i,j)
|
||||
for (Sgi::vector<const state*>::iterator j = tgba_state_.begin();
|
||||
j != tgba_state_.end(); ++j)
|
||||
{
|
||||
spoiler_node* n1 = new spoiler_node(*i,
|
||||
*j,
|
||||
nb_node_parity_game++);
|
||||
spoiler_vertice_.push_back(n1);
|
||||
}
|
||||
|
||||
// duplicator node are all state couple where
|
||||
// the first state i are reachable.
|
||||
trans = new Sgi::vector<couple_bdd*>;
|
||||
for (Sgi::vector<const state*>::iterator j = tgba_state_.begin();
|
||||
j != tgba_state_.end(); ++j)
|
||||
{
|
||||
si = automata_->succ_iter(*j);
|
||||
for (si->first(); !si->done(); si->next())
|
||||
{
|
||||
|
||||
// if there exist a predecessor of i named j
|
||||
s = si->current_state();
|
||||
if (s->compare(*i) == 0)
|
||||
{
|
||||
|
||||
// p is the label of the transition j->i
|
||||
p = new couple_bdd(si->current_condition(),
|
||||
si->current_acceptance_conditions());
|
||||
|
||||
// If an other predecessor of i has the same label p
|
||||
// to reach i, then we don't compute the duplicator node.
|
||||
exist = false;
|
||||
for (Sgi::vector<couple_bdd*>::iterator v
|
||||
= trans->begin();
|
||||
v != trans->end(); ++v)
|
||||
{
|
||||
if ((si->current_condition() == (*v)->first) &&
|
||||
(si->current_acceptance_conditions()
|
||||
== (*v)->second))
|
||||
exist = true;
|
||||
}
|
||||
|
||||
if (!exist)
|
||||
{
|
||||
// We build all the state couple with the label p.
|
||||
trans->push_back(p);
|
||||
for (Sgi::vector<const state*>::iterator s
|
||||
= tgba_state_.begin();
|
||||
s != tgba_state_.end(); ++s)
|
||||
{
|
||||
duplicator_node* n2
|
||||
= new duplicator_node(*i,
|
||||
*s,
|
||||
si->current_condition(),
|
||||
si->current_acceptance_conditions(),
|
||||
nb_node_parity_game++);
|
||||
duplicator_vertice_.push_back(n2);
|
||||
}
|
||||
}
|
||||
else
|
||||
delete p;
|
||||
}
|
||||
delete s;
|
||||
}
|
||||
delete si;
|
||||
}
|
||||
Sgi::vector<couple_bdd*>::iterator i2;
|
||||
for (i2 = trans->begin(); i2 != trans->end(); ++i2)
|
||||
{
|
||||
delete *i2;
|
||||
}
|
||||
delete trans;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parity_game_graph_direct::build_link()
|
||||
{
|
||||
int nb_ds = 0;
|
||||
int nb_sd = 0;
|
||||
spot::state* s = NULL;
|
||||
|
||||
// for each couple of (spoiler, duplicator)
|
||||
for (Sgi::vector<spoiler_node*>::iterator i
|
||||
= spoiler_vertice_.begin(); i != spoiler_vertice_.end(); ++i)
|
||||
{
|
||||
for (Sgi::vector<duplicator_node*>::iterator j
|
||||
= duplicator_vertice_.begin();
|
||||
j != duplicator_vertice_.end(); ++j)
|
||||
{
|
||||
// We add a link between a duplicator and a spoiler.
|
||||
if ((*j)->get_spoiler_node()->compare((*i)->get_spoiler_node()) == 0)
|
||||
{
|
||||
tgba_succ_iterator* si
|
||||
= automata_->succ_iter((*j)->get_duplicator_node());
|
||||
for (si->first(); !si->done(); si->next())
|
||||
{
|
||||
s = si->current_state();
|
||||
if ((s->compare((*i)->get_duplicator_node()) == 0) &&
|
||||
(*j)->implies(si->current_condition(),
|
||||
si->current_acceptance_conditions()))
|
||||
{
|
||||
(*j)->add_succ(*i);
|
||||
nb_ds++;
|
||||
}
|
||||
delete s;
|
||||
}
|
||||
delete si;
|
||||
}
|
||||
|
||||
// We add a link between a spoiler and a duplicator.
|
||||
if ((*j)->get_duplicator_node()->compare((*i)->get_duplicator_node()) == 0)
|
||||
{
|
||||
tgba_succ_iterator* si
|
||||
= automata_->succ_iter((*i)->get_spoiler_node());
|
||||
for (si->first(); !si->done(); si->next())
|
||||
{
|
||||
s = si->current_state();
|
||||
if ((s->compare((*j)->get_spoiler_node()) == 0) &&
|
||||
(*j)->match(si->current_condition(),
|
||||
si->current_acceptance_conditions()))
|
||||
{
|
||||
(*i)->add_succ(*j);
|
||||
nb_sd++;
|
||||
}
|
||||
delete s;
|
||||
}
|
||||
delete si;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parity_game_graph_direct::prune()
|
||||
{
|
||||
bool change = true;
|
||||
|
||||
while (change)
|
||||
{
|
||||
change = false;
|
||||
for (Sgi::vector<duplicator_node*>::iterator i
|
||||
= duplicator_vertice_.begin();
|
||||
i != duplicator_vertice_.end(); ++i)
|
||||
{
|
||||
change |= (*i)->set_win();
|
||||
}
|
||||
for (Sgi::vector<spoiler_node*>::iterator i
|
||||
= spoiler_vertice_.begin();
|
||||
i != spoiler_vertice_.end(); ++i)
|
||||
{
|
||||
change |= (*i)->set_win();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
simulation_relation*
|
||||
parity_game_graph_direct::get_relation()
|
||||
{
|
||||
simulation_relation* rel = new simulation_relation();
|
||||
state_couple* p = NULL;
|
||||
seen_map::iterator j;
|
||||
|
||||
for (Sgi::vector<spoiler_node*>::iterator i
|
||||
= spoiler_vertice_.begin();
|
||||
i != spoiler_vertice_.end(); ++i)
|
||||
{
|
||||
if (!(*i)->not_win)
|
||||
{
|
||||
p = new state_couple((*i)->get_spoiler_node(),
|
||||
(*i)->get_duplicator_node());
|
||||
rel->push_back(p);
|
||||
|
||||
|
||||
// We remove the state in rel from seen
|
||||
// because the destructor of
|
||||
// tgba_reachable_iterator_breadth_first
|
||||
// delete all the state.
|
||||
|
||||
|
||||
if ((j = seen.find(p->first)) != seen.end())
|
||||
seen.erase(j);
|
||||
if ((j = seen.find(p->second)) != seen.end())
|
||||
seen.erase(j);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return rel;
|
||||
}
|
||||
|
||||
parity_game_graph_direct::~parity_game_graph_direct()
|
||||
{
|
||||
}
|
||||
|
||||
parity_game_graph_direct::parity_game_graph_direct(const tgba* a)
|
||||
: parity_game_graph(a)
|
||||
{
|
||||
this->build_couple();
|
||||
this->build_link();
|
||||
this->prune();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
simulation_relation*
|
||||
get_direct_relation_simulation(const tgba* f, int opt)
|
||||
{
|
||||
parity_game_graph_direct* G = new parity_game_graph_direct(f);
|
||||
simulation_relation* rel = G->get_relation();
|
||||
if (opt == 1)
|
||||
G->print(std::cout);
|
||||
delete G;
|
||||
return rel;
|
||||
}
|
||||
|
||||
void
|
||||
free_relation_simulation(simulation_relation* rel)
|
||||
{
|
||||
if (rel == NULL)
|
||||
return;
|
||||
|
||||
Sgi::hash_map<const spot::state*, int,
|
||||
state_ptr_hash, state_ptr_equal> seen;
|
||||
Sgi::hash_map<const spot::state*, int,
|
||||
state_ptr_hash, state_ptr_equal>::iterator j;
|
||||
|
||||
simulation_relation::iterator i;
|
||||
for (i = rel->begin(); i != rel->end(); ++i)
|
||||
{
|
||||
if ((j = seen.find((*i)->first)) == seen.end())
|
||||
seen[(*i)->first] = 0;
|
||||
|
||||
if ((j = seen.find((*i)->second)) == seen.end())
|
||||
seen[(*i)->second] = 0;
|
||||
|
||||
delete *i;
|
||||
}
|
||||
delete rel;
|
||||
rel = NULL;
|
||||
|
||||
for (j = seen.begin(); j != seen.end();)
|
||||
{
|
||||
const state* ptr = j->first;
|
||||
++j;
|
||||
delete(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_include(const tgba*, const tgba*)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
tgba*
|
||||
reduc_tgba_sim(const tgba* f, int opt)
|
||||
{
|
||||
spot::tgba_reduc* automatareduc = new spot::tgba_reduc(f);
|
||||
|
||||
if (opt & Reduce_Dir_Sim)
|
||||
{
|
||||
simulation_relation* rel
|
||||
= get_direct_relation_simulation(automatareduc);
|
||||
|
||||
automatareduc->display_rel_sim(rel, std::cout);
|
||||
automatareduc->prune_automata(rel);
|
||||
|
||||
free_relation_simulation(rel);
|
||||
}
|
||||
else
|
||||
if (opt & Reduce_Del_Sim)
|
||||
{
|
||||
simulation_relation* rel
|
||||
= get_delayed_relation_simulation(automatareduc);
|
||||
|
||||
automatareduc->display_rel_sim(rel, std::cout);
|
||||
automatareduc->prune_automata(rel);
|
||||
|
||||
free_relation_simulation(rel);
|
||||
}
|
||||
|
||||
if (opt & Reduce_Scc)
|
||||
{
|
||||
automatareduc->compute_scc();
|
||||
automatareduc->prune_scc();
|
||||
}
|
||||
|
||||
return automatareduc;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue