spot/src/tgbaalgos/reductgba_sim.cc
Alexandre Duret-Lutz 3f2cba6304 * src/sanity/style.test: Suggest ++i over i++ when it does not
matter, for consistency.
* src/tgbaalgos/tarjan_on_fly.cc, iface/gspn/ssp.cc,
src/tgbaalgos/reductgba_sim_del.cc, src/tgbaalgos/reductgba_sim.cc,
src/tgbaalgos/minimalce.cc, src/tgba/tgbareduc.cc: Adjust.
2004-09-23 12:20:10 +00:00

703 lines
16 KiB
C++

// 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 sn_v;
lnode_pred = new sn_v;
not_win = false;
}
spoiler_node::~spoiler_node()
{
lnode_succ->clear();
lnode_pred->clear();
delete lnode_succ;
delete lnode_pred;
delete sc_;
}
bool
spoiler_node::add_succ(spoiler_node* n)
{
bool exist = false;
for (sn_v::iterator i = lnode_succ->begin();
i != lnode_succ->end(); ++i)
if ((*i == n) ||
((*i)->compare(n) == true))
exist = true;
if (exist)
return false;
lnode_succ->push_back(n);
n->add_pred(this);
return true;
}
void
spoiler_node::del_succ(spoiler_node* n)
{
for (sn_v::iterator i = lnode_succ->begin();
i != lnode_succ->end();)
{
if (*i == n)
{
i = lnode_succ->erase(i);
}
else
++i;
}
}
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;
}
if (change != not_win)
for (Sgi::vector<spoiler_node*>::iterator i = lnode_pred->begin();
i != lnode_pred->end(); ++i)
(*i)->set_win();
return change != not_win;
}
std::string
spoiler_node::to_string(const tgba* a)
{
std::ostringstream os;
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();
}
bool
spoiler_node::compare(spoiler_node* n)
{
return (((sc_->first)->compare((n->get_pair())->first) == 0) &&
((sc_->second)->compare((n->get_pair())->second) == 0));
}
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;
}
}
if (change != not_win)
for (Sgi::vector<spoiler_node*>::iterator i = lnode_pred->begin();
i != lnode_pred->end(); ++i)
(*i)->set_win();
return change != not_win;
}
std::string
duplicator_node::to_string(const tgba* a)
{
std::ostringstream os;
os << num_
<< " [shape=box, label=\"("
<< a->format_state(sc_->first)
<< ", "
<< a->format_state(sc_->second)
<< ", ";
bdd_print_acc(os, a->get_dict(), label_);
os << ", ";
bdd_print_acc(os, a->get_dict(), acc_);
os << ")\"]"
<< std::endl;
return os.str();
}
bool
duplicator_node::compare(spoiler_node* n)
{
return (this->spoiler_node::compare(n) &&
(label_ == dynamic_cast<duplicator_node*>(n)->get_label()) &&
(acc_ == dynamic_cast<duplicator_node*>(n)->get_acc()));
}
bdd
duplicator_node::get_label() const
{
return label_;
}
bdd
duplicator_node::get_acc() const
{
return acc_;
}
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_graph()
{
tgba_succ_iterator* si = 0;
typedef Sgi::pair<bdd, bdd> couple_bdd;
couple_bdd *p = 0;
Sgi::vector<couple_bdd*>* trans = 0;
bool exist = false;
spot::state* s = 0;
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 = 0;
// 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::lift()
{
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();
}
}
}
direct_simulation_relation*
parity_game_graph_direct::get_relation()
{
direct_simulation_relation* rel = new direct_simulation_relation;
state_couple* p = 0;
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 instance of 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_graph();
this->build_link();
this->lift();
}
///////////////////////////////////////////////////////////////////////
direct_simulation_relation*
get_direct_relation_simulation(const tgba* f,
std::ostream& os,
int opt)
{
parity_game_graph_direct* G = new parity_game_graph_direct(f);
direct_simulation_relation* rel = G->get_relation();
if (opt == 1)
G->print(os);
delete G;
return rel;
}
void
free_relation_simulation(direct_simulation_relation* rel)
{
if (rel == 0)
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 = 0;
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_quotient_Dir_Sim | Reduce_transition_Dir_Sim))
{
direct_simulation_relation* rel
= get_direct_relation_simulation(automatareduc, std::cout);
automatareduc->display_rel_sim(rel, std::cout);
automatareduc->quotient_state(rel);
automatareduc->delete_transitions(rel);
free_relation_simulation(rel);
}
else
if (opt & (Reduce_quotient_Del_Sim | Reduce_transition_Del_Sim))
{
delayed_simulation_relation* rel
= get_delayed_relation_simulation(automatareduc, std::cout);
automatareduc->display_rel_sim(rel, std::cout);
automatareduc->quotient_state(rel);
automatareduc->delete_transitions(rel);
free_relation_simulation(rel);
}
if (opt & Reduce_Scc)
{
automatareduc->prune_scc();
}
return automatareduc;
}
}