* 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
20
ChangeLog
20
ChangeLog
|
|
@ -1,3 +1,23 @@
|
||||||
|
2004-06-15 Thomas Martinez <martinez@src.lip6.fr>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2004-06-02 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
2004-06-02 Alexandre Duret-Lutz <adl@src.lip6.fr>
|
||||||
|
|
||||||
* iface/gspn/common.cc, iface/gspn/common.hh: Remove the
|
* iface/gspn/common.cc, iface/gspn/common.hh: Remove the
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ check_PROGRAMS = \
|
||||||
lunabbrev \
|
lunabbrev \
|
||||||
nenoform \
|
nenoform \
|
||||||
reduc \
|
reduc \
|
||||||
|
reduccmp \
|
||||||
syntimpl \
|
syntimpl \
|
||||||
tostring \
|
tostring \
|
||||||
tunabbrev \
|
tunabbrev \
|
||||||
|
|
@ -49,6 +50,8 @@ lunabbrev_CPPFLAGS = $(AM_CPPFLAGS) -DLUNABBREV
|
||||||
nenoform_SOURCES = equals.cc
|
nenoform_SOURCES = equals.cc
|
||||||
nenoform_CPPFLAGS = $(AM_CPPFLAGS) -DNENOFORM
|
nenoform_CPPFLAGS = $(AM_CPPFLAGS) -DNENOFORM
|
||||||
reduc_SOURCES = reduc.cc
|
reduc_SOURCES = reduc.cc
|
||||||
|
reduccmp_SOURCES = equals.cc
|
||||||
|
reduccmp_CPPFLAGS = $(AM_CPPFLAGS) -DREDUC
|
||||||
syntimpl_SOURCES = syntimpl.cc
|
syntimpl_SOURCES = syntimpl.cc
|
||||||
tostring_SOURCES = tostring.cc
|
tostring_SOURCES = tostring.cc
|
||||||
tunabbrev_SOURCES = equals.cc
|
tunabbrev_SOURCES = equals.cc
|
||||||
|
|
@ -70,6 +73,7 @@ TESTS = \
|
||||||
nenoform.test \
|
nenoform.test \
|
||||||
tunenoform.test \
|
tunenoform.test \
|
||||||
syntimpl.test \
|
syntimpl.test \
|
||||||
reduc.test
|
reduc.test \
|
||||||
|
reduccmp.test
|
||||||
|
|
||||||
CLEANFILES = stdout expect parse.dot result.data
|
CLEANFILES = stdout expect parse.dot result.data
|
||||||
|
|
|
||||||
|
|
@ -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
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
// et Marie Curie.
|
// et Marie Curie.
|
||||||
//
|
//
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include "ltlvisit/nenoform.hh"
|
#include "ltlvisit/nenoform.hh"
|
||||||
#include "ltlvisit/destroy.hh"
|
#include "ltlvisit/destroy.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
#include "ltlast/allnodes.hh"
|
||||||
|
#include "ltlvisit/reducform.hh"
|
||||||
|
#include "ltlvisit/tostring.hh"
|
||||||
|
|
||||||
void
|
void
|
||||||
syntax(char* prog)
|
syntax(char* prog)
|
||||||
|
|
@ -42,7 +44,6 @@ main(int argc, char** argv)
|
||||||
if (argc != 3)
|
if (argc != 3)
|
||||||
syntax(argv[0]);
|
syntax(argv[0]);
|
||||||
|
|
||||||
|
|
||||||
spot::ltl::parse_error_list p1;
|
spot::ltl::parse_error_list p1;
|
||||||
spot::ltl::formula* f1 = spot::ltl::parse(argv[1], p1);
|
spot::ltl::formula* f1 = spot::ltl::parse(argv[1], p1);
|
||||||
|
|
||||||
|
|
@ -79,6 +80,16 @@ main(int argc, char** argv)
|
||||||
spot::ltl::dump(std::cout, f1);
|
spot::ltl::dump(std::cout, f1);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef REDUC
|
||||||
|
spot::ltl::formula* tmp;
|
||||||
|
tmp = f1;
|
||||||
|
f1 = spot::ltl::reduce(f1);
|
||||||
|
//std::string f2s = spot::ltl::to_string(f2);
|
||||||
|
//std::string f1s = spot::ltl::to_string(f1);
|
||||||
|
spot::ltl::destroy(tmp);
|
||||||
|
spot::ltl::dump(std::cout, f1);
|
||||||
|
//std::cout << f1s << " // " << f2s << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
int exit_code = f1 != f2;
|
int exit_code = f1 != f2;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,12 +133,12 @@ main(int argc, char** argv)
|
||||||
f2s = spot::ltl::to_string(f2);
|
f2s = spot::ltl::to_string(f2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (red && !f2)
|
if ((red | !red) && !f2)
|
||||||
{
|
{
|
||||||
std::cout << length_f1_before << " " << length_f1_after
|
std::cout << length_f1_before << " " << length_f1_after
|
||||||
<< " '" << f1s_before << "' reduce to '" << f1s_after << "'"
|
<< " '" << f1s_before << "' reduce to '" << f1s_after << "'"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f2)
|
if (f2)
|
||||||
{
|
{
|
||||||
|
|
@ -179,5 +179,6 @@ main(int argc, char** argv)
|
||||||
assert(spot::ltl::binop::instance_count() == 0);
|
assert(spot::ltl::binop::instance_count() == 0);
|
||||||
assert(spot::ltl::multop::instance_count() == 0);
|
assert(spot::ltl::multop::instance_count() == 0);
|
||||||
|
|
||||||
return exit_code;
|
//return exit_code;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
74
src/ltltest/reduccmp.test
Executable file
74
src/ltltest/reduccmp.test
Executable file
|
|
@ -0,0 +1,74 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
# Check for the equals visitor
|
||||||
|
|
||||||
|
. ./defs || exit 1
|
||||||
|
|
||||||
|
# Basics reduction
|
||||||
|
run 0 ./reduccmp 'X(true)' 'true'
|
||||||
|
run 0 ./reduccmp 'X(false)' 'false'
|
||||||
|
run 0 ./reduccmp 'F(true)' 'true'
|
||||||
|
run 0 ./reduccmp 'F(false)' 'false'
|
||||||
|
run 0 ./reduccmp 'G(true)' 'true'
|
||||||
|
run 0 ./reduccmp 'G(false)' 'false'
|
||||||
|
|
||||||
|
run 0 ./reduccmp 'XGF(f)' 'GF(f)'
|
||||||
|
run 0 ./reduccmp 'FX(a)' 'XF(a)'
|
||||||
|
run 0 ./reduccmp 'G(a R b)' 'G(b)'
|
||||||
|
run 0 ./reduccmp 'GX(a)' 'XG(a)'
|
||||||
|
|
||||||
|
run 0 ./reduccmp 'X(a) U X(b)' 'X(a U b)'
|
||||||
|
run 0 ./reduccmp 'X(a) R X(b)' 'X(a R b)'
|
||||||
|
|
||||||
|
run 0 ./reduccmp 'Xa & Xb' 'X(a & b)'
|
||||||
|
run 0 ./reduccmp '(a U b) & (c U b)' '(a & c) U b'
|
||||||
|
run 0 ./reduccmp '(a R b) & (a R c)' 'a R (b & c)'
|
||||||
|
run 0 ./reduccmp 'Xa | Xb' 'X(a | b)'
|
||||||
|
run 0 ./reduccmp '(a U b) | (a U c)' 'a U (b | c)'
|
||||||
|
run 0 ./reduccmp '(a R b) | (c R b)' '(a | c) R b'
|
||||||
|
|
||||||
|
run 0 ./reduccmp 'X(a & GFb)' 'Xa & GFb'
|
||||||
|
run 0 ./reduccmp 'X(a | GFb)' 'Xa | GFb'
|
||||||
|
run 0 ./reduccmp 'F(a & GFb)' 'Fa & GFb'
|
||||||
|
run 0 ./reduccmp 'G(a | GFb)' 'Ga | GFb'
|
||||||
|
|
||||||
|
run 0 ./reduccmp 'X(a & GFb & c)' 'X(a & c) & GFb'
|
||||||
|
run 0 ./reduccmp 'X(a | GFb | c)' 'X(a | c) | GFb'
|
||||||
|
run 0 ./reduccmp 'F(a & GFb & c)' 'F(a & c) & GFb'
|
||||||
|
run 0 ./reduccmp 'G(a | GFb | c)' 'G(a | c) | GFb'
|
||||||
|
|
||||||
|
# Eventuality and universality class reduction
|
||||||
|
run 0 ./reduccmp 'FFa' 'Fa'
|
||||||
|
run 0 ./reduccmp 'FGFa' 'GFa'
|
||||||
|
run 0 ./reduccmp 'b U Fa' 'Fa'
|
||||||
|
run 0 ./reduccmp 'b U GFa' 'GFa'
|
||||||
|
run 0 ./reduccmp 'Ga' 'Ga'
|
||||||
|
run 0 ./reduccmp 'GFGa' 'FGa'
|
||||||
|
run 0 ./reduccmp 'b R Ga' 'Ga'
|
||||||
|
run 0 ./reduccmp 'b R FGa' 'FGa'
|
||||||
|
|
||||||
|
# Syntactic reduction
|
||||||
|
run 0 ./reduccmp 'a & (b U a)' 'a'
|
||||||
|
run 0 ./reduccmp 'a | (b U a)' '(b U a)'
|
||||||
|
run 0 ./reduccmp 'a U (b U a)' '(b U a)'
|
||||||
|
|
@ -23,7 +23,9 @@
|
||||||
#include "ltlast/allnodes.hh"
|
#include "ltlast/allnodes.hh"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "ltlvisit/clone.hh"
|
||||||
#include "ltlvisit/destroy.hh"
|
#include "ltlvisit/destroy.hh"
|
||||||
|
#include "ltlvisit/dump.hh"
|
||||||
|
|
||||||
namespace spot
|
namespace spot
|
||||||
{
|
{
|
||||||
|
|
@ -85,6 +87,33 @@ namespace spot
|
||||||
result_ = c;
|
result_ = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formula*
|
||||||
|
param_case(multop* mo, unop::type op, multop::type op_child)
|
||||||
|
{
|
||||||
|
formula* result;
|
||||||
|
multop::vec* res1 = new multop::vec;
|
||||||
|
multop::vec* resGF = new multop::vec;
|
||||||
|
unsigned mos = mo->size();
|
||||||
|
for (unsigned i = 0; i < mos; ++i)
|
||||||
|
if (is_GF(mo->nth(i)))
|
||||||
|
resGF->push_back(clone(mo->nth(i)));
|
||||||
|
else
|
||||||
|
res1->push_back(clone(mo->nth(i)));
|
||||||
|
destroy(mo);
|
||||||
|
multop::vec* res3 = new multop::vec;
|
||||||
|
if (res1->size())
|
||||||
|
res3->push_back(unop::instance(op,
|
||||||
|
multop::instance(op_child, res1)));
|
||||||
|
else
|
||||||
|
delete res1;
|
||||||
|
if (resGF->size())
|
||||||
|
res3->push_back(multop::instance(op_child, resGF));
|
||||||
|
else
|
||||||
|
delete resGF;
|
||||||
|
result = multop::instance(op_child, res3);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
visit(unop* uo)
|
visit(unop* uo)
|
||||||
{
|
{
|
||||||
|
|
@ -112,30 +141,10 @@ namespace spot
|
||||||
// X(f1 & GF(f2)) = X(f1) & GF(F2)
|
// X(f1 & GF(f2)) = X(f1) & GF(F2)
|
||||||
// X(f1 | GF(f2)) = X(f1) | GF(F2)
|
// X(f1 | GF(f2)) = X(f1) | GF(F2)
|
||||||
mo = dynamic_cast<multop*>(result_);
|
mo = dynamic_cast<multop*>(result_);
|
||||||
if (mo && mo->size() == 2)
|
if (mo)
|
||||||
{
|
{
|
||||||
// FIXME: This is incomplete. It should be done for
|
result_ = param_case(mo, unop::X, mo->op());
|
||||||
// multops of any size.
|
return;
|
||||||
if (is_GF(mo->nth(0)))
|
|
||||||
{
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
res->push_back(unop::instance(unop::F,
|
|
||||||
basic_reduce(mo->nth(1))));
|
|
||||||
res->push_back(basic_reduce(mo->nth(0)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
destroy(mo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (is_GF(mo->nth(1)))
|
|
||||||
{
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
res->push_back(unop::instance(unop::F,
|
|
||||||
basic_reduce(mo->nth(0))));
|
|
||||||
res->push_back(basic_reduce(mo->nth(1)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
destroy(mo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result_ = unop::instance(unop::X, result_);
|
result_ = unop::instance(unop::X, result_);
|
||||||
|
|
@ -161,34 +170,12 @@ namespace spot
|
||||||
|
|
||||||
// F(f1 & GF(f2)) = F(f1) & GF(F2)
|
// F(f1 & GF(f2)) = F(f1) & GF(F2)
|
||||||
mo = dynamic_cast<multop*>(result_);
|
mo = dynamic_cast<multop*>(result_);
|
||||||
if (mo && mo->op() == multop::And
|
if (mo && mo->op() == multop::And)
|
||||||
// FIXME: This is incomplete. It should be done for
|
|
||||||
// "And"s of any size.
|
|
||||||
&& mo->size() == 2)
|
|
||||||
{
|
{
|
||||||
if (is_GF(mo->nth(0)))
|
result_ = param_case(mo, unop::F, multop::And);
|
||||||
{
|
return;
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
res->push_back(unop::instance(unop::F,
|
|
||||||
basic_reduce(mo->nth(1))));
|
|
||||||
res->push_back(basic_reduce(mo->nth(0)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
destroy(mo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (is_GF(mo->nth(1)))
|
|
||||||
{
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
res->push_back(unop::instance(unop::F,
|
|
||||||
basic_reduce(mo->nth(0))));
|
|
||||||
res->push_back(basic_reduce(mo->nth(1)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
destroy(mo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_ = unop::instance(unop::F, result_);
|
result_ = unop::instance(unop::F, result_);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -222,31 +209,10 @@ namespace spot
|
||||||
|
|
||||||
// G(f1 | GF(f2)) = G(f1) | GF(F2)
|
// G(f1 | GF(f2)) = G(f1) | GF(F2)
|
||||||
mo = dynamic_cast<multop*>(result_);
|
mo = dynamic_cast<multop*>(result_);
|
||||||
if (mo && mo->op() == multop::Or
|
if (mo && mo->op() == multop::Or)
|
||||||
// FIXME: This is incomplete. It should be done for
|
|
||||||
// "Or"s of any size.
|
|
||||||
&& mo->size() == 2)
|
|
||||||
{
|
{
|
||||||
if (is_GF(mo->nth(0)))
|
result_ = param_case(mo, unop::G, multop::Or);
|
||||||
{
|
return;
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
res->push_back(unop::instance(unop::F,
|
|
||||||
basic_reduce(mo->nth(1))));
|
|
||||||
res->push_back(basic_reduce(mo->nth(0)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
destroy(mo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (is_GF(mo->nth(1)))
|
|
||||||
{
|
|
||||||
multop::vec* res = new multop::vec;
|
|
||||||
res->push_back(unop::instance(unop::F,
|
|
||||||
basic_reduce(mo->nth(0))));
|
|
||||||
res->push_back(basic_reduce(mo->nth(1)));
|
|
||||||
result_ = multop::instance(mo->op(), res);
|
|
||||||
destroy(mo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result_ = unop::instance(unop::G, result_);
|
result_ = unop::instance(unop::G, result_);
|
||||||
|
|
@ -385,17 +351,17 @@ namespace spot
|
||||||
if (uo && uo->op() == unop::X)
|
if (uo && uo->op() == unop::X)
|
||||||
{
|
{
|
||||||
// Xa & Xb = X(a & b)
|
// Xa & Xb = X(a & b)
|
||||||
tmpX->push_back(basic_reduce(uo->child()));
|
tmpX->push_back(clone(uo->child()));
|
||||||
}
|
}
|
||||||
else if (is_FG(*i))
|
else if (is_FG(*i))
|
||||||
{
|
{
|
||||||
// FG(a) & FG(b) = FG(a & b)
|
// FG(a) & FG(b) = FG(a & b)
|
||||||
unop* uo2 = dynamic_cast<unop*>(uo->child());
|
unop* uo2 = dynamic_cast<unop*>(uo->child());
|
||||||
tmpFG->push_back(basic_reduce(uo2->child()));
|
tmpFG->push_back(clone(uo2->child()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmpOther->push_back(basic_reduce(*i));
|
tmpOther->push_back(clone(*i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bo)
|
else if (bo)
|
||||||
|
|
@ -414,7 +380,7 @@ namespace spot
|
||||||
&& ftmp == bo2->second())
|
&& ftmp == bo2->second())
|
||||||
{
|
{
|
||||||
tmpUright
|
tmpUright
|
||||||
->push_back(basic_reduce(bo2->first()));
|
->push_back(clone(bo2->first()));
|
||||||
if (j != i)
|
if (j != i)
|
||||||
{
|
{
|
||||||
destroy(*j);
|
destroy(*j);
|
||||||
|
|
@ -428,7 +394,7 @@ namespace spot
|
||||||
instance(multop::
|
instance(multop::
|
||||||
And,
|
And,
|
||||||
tmpUright),
|
tmpUright),
|
||||||
basic_reduce(ftmp)));
|
clone(ftmp)));
|
||||||
}
|
}
|
||||||
else if (bo->op() == binop::R)
|
else if (bo->op() == binop::R)
|
||||||
{
|
{
|
||||||
|
|
@ -444,7 +410,7 @@ namespace spot
|
||||||
&& ftmp == bo2->first())
|
&& ftmp == bo2->first())
|
||||||
{
|
{
|
||||||
tmpRright
|
tmpRright
|
||||||
->push_back(basic_reduce(bo2->second()));
|
->push_back(clone(bo2->second()));
|
||||||
if (j != i)
|
if (j != i)
|
||||||
{
|
{
|
||||||
destroy(*j);
|
destroy(*j);
|
||||||
|
|
@ -454,19 +420,19 @@ namespace spot
|
||||||
}
|
}
|
||||||
tmpR
|
tmpR
|
||||||
->push_back(binop::instance(binop::R,
|
->push_back(binop::instance(binop::R,
|
||||||
basic_reduce(ftmp),
|
clone(ftmp),
|
||||||
multop::
|
multop::
|
||||||
instance(multop::And,
|
instance(multop::And,
|
||||||
tmpRright)));
|
tmpRright)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmpOther->push_back(basic_reduce(*i));
|
tmpOther->push_back(clone(*i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmpOther->push_back(basic_reduce(*i));
|
tmpOther->push_back(clone(*i));
|
||||||
}
|
}
|
||||||
destroy(*i);
|
destroy(*i);
|
||||||
}
|
}
|
||||||
|
|
@ -489,17 +455,17 @@ namespace spot
|
||||||
if (uo && uo->op() == unop::X)
|
if (uo && uo->op() == unop::X)
|
||||||
{
|
{
|
||||||
// Xa | Xb = X(a | b)
|
// Xa | Xb = X(a | b)
|
||||||
tmpX->push_back(basic_reduce(uo->child()));
|
tmpX->push_back(clone(uo->child()));
|
||||||
}
|
}
|
||||||
else if (is_GF(*i))
|
else if (is_GF(*i))
|
||||||
{
|
{
|
||||||
// GF(a) | GF(b) = GF(a | b)
|
// GF(a) | GF(b) = GF(a | b)
|
||||||
unop* uo2 = dynamic_cast<unop*>(uo->child());
|
unop* uo2 = dynamic_cast<unop*>(uo->child());
|
||||||
tmpGF->push_back(basic_reduce(uo2->child()));
|
tmpGF->push_back(clone(uo2->child()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmpOther->push_back(basic_reduce(*i));
|
tmpOther->push_back(clone(*i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bo)
|
else if (bo)
|
||||||
|
|
@ -518,7 +484,7 @@ namespace spot
|
||||||
&& ftmp == bo2->first())
|
&& ftmp == bo2->first())
|
||||||
{
|
{
|
||||||
tmpUright
|
tmpUright
|
||||||
->push_back(basic_reduce(bo2->second()));
|
->push_back(clone(bo2->second()));
|
||||||
if (j != i)
|
if (j != i)
|
||||||
{
|
{
|
||||||
destroy(*j);
|
destroy(*j);
|
||||||
|
|
@ -527,7 +493,7 @@ namespace spot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmpU->push_back(binop::instance(binop::U,
|
tmpU->push_back(binop::instance(binop::U,
|
||||||
basic_reduce(ftmp),
|
clone(ftmp),
|
||||||
multop::
|
multop::
|
||||||
instance(multop::Or,
|
instance(multop::Or,
|
||||||
tmpUright)));
|
tmpUright)));
|
||||||
|
|
@ -546,7 +512,7 @@ namespace spot
|
||||||
&& ftmp == bo2->second())
|
&& ftmp == bo2->second())
|
||||||
{
|
{
|
||||||
tmpRright
|
tmpRright
|
||||||
->push_back(basic_reduce(bo->first()));
|
->push_back(clone(bo2->first()));
|
||||||
if (j != i)
|
if (j != i)
|
||||||
{
|
{
|
||||||
destroy(*j);
|
destroy(*j);
|
||||||
|
|
@ -559,16 +525,16 @@ namespace spot
|
||||||
multop::
|
multop::
|
||||||
instance(multop::Or,
|
instance(multop::Or,
|
||||||
tmpRright),
|
tmpRright),
|
||||||
basic_reduce(ftmp)));
|
clone(ftmp)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmpOther->push_back(basic_reduce(*i));
|
tmpOther->push_back(clone(*i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmpOther->push_back(basic_reduce(*i));
|
tmpOther->push_back(clone(*i));
|
||||||
}
|
}
|
||||||
destroy(*i);
|
destroy(*i);
|
||||||
}
|
}
|
||||||
|
|
@ -582,23 +548,27 @@ namespace spot
|
||||||
res->clear();
|
res->clear();
|
||||||
delete res;
|
delete res;
|
||||||
|
|
||||||
if (tmpX->size())
|
|
||||||
|
if (tmpX && tmpX->size())
|
||||||
tmpOther->push_back(unop::instance(unop::X,
|
tmpOther->push_back(unop::instance(unop::X,
|
||||||
multop::instance(mo->op(),
|
multop::instance(mo->op(),
|
||||||
tmpX)));
|
tmpX)));
|
||||||
else
|
else if (tmpX && !tmpX->size())
|
||||||
delete tmpX;
|
delete tmpX;
|
||||||
|
|
||||||
if (tmpU->size())
|
|
||||||
|
if (tmpU && tmpU->size())
|
||||||
tmpOther->push_back(multop::instance(mo->op(), tmpU));
|
tmpOther->push_back(multop::instance(mo->op(), tmpU));
|
||||||
else
|
else if (tmpU && !tmpU->size())
|
||||||
delete tmpU;
|
delete tmpU;
|
||||||
|
|
||||||
if (tmpR->size())
|
|
||||||
|
if (tmpR && tmpR->size())
|
||||||
tmpOther->push_back(multop::instance(mo->op(), tmpR));
|
tmpOther->push_back(multop::instance(mo->op(), tmpR));
|
||||||
else
|
else if (tmpR && !tmpR->size())
|
||||||
delete tmpR;
|
delete tmpR;
|
||||||
|
|
||||||
|
|
||||||
if (tmpGF && tmpGF->size())
|
if (tmpGF && tmpGF->size())
|
||||||
{
|
{
|
||||||
formula* ftmp
|
formula* ftmp
|
||||||
|
|
@ -608,6 +578,10 @@ namespace spot
|
||||||
tmpGF)));
|
tmpGF)));
|
||||||
tmpOther->push_back(ftmp);
|
tmpOther->push_back(ftmp);
|
||||||
}
|
}
|
||||||
|
else if (tmpGF && !tmpGF->size())
|
||||||
|
delete tmpGF;
|
||||||
|
|
||||||
|
|
||||||
if (tmpFG && tmpFG->size())
|
if (tmpFG && tmpFG->size())
|
||||||
{
|
{
|
||||||
formula* ftmp
|
formula* ftmp
|
||||||
|
|
@ -617,6 +591,9 @@ namespace spot
|
||||||
tmpFG)));
|
tmpFG)));
|
||||||
tmpOther->push_back(ftmp);
|
tmpOther->push_back(ftmp);
|
||||||
}
|
}
|
||||||
|
else if (tmpFG && !tmpFG->size())
|
||||||
|
delete tmpFG;
|
||||||
|
|
||||||
|
|
||||||
result_ = multop::instance(op, tmpOther);
|
result_ = multop::instance(op, tmpOther);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,7 @@ namespace spot
|
||||||
destroy(f2);
|
destroy(f2);
|
||||||
f2 = f1;
|
f2 = f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt & (Reduce_Syntactic_Implications
|
if (opt & (Reduce_Syntactic_Implications
|
||||||
| Reduce_Eventuality_And_Universality))
|
| Reduce_Eventuality_And_Universality))
|
||||||
{
|
{
|
||||||
|
|
@ -322,9 +323,9 @@ namespace spot
|
||||||
|
|
||||||
// Run basic_reduce again.
|
// Run basic_reduce again.
|
||||||
//
|
//
|
||||||
// Consider `F b & g' were g is an eventual formula rewritten
|
// Consider `FG b & g' were g is an eventual formula rewritten
|
||||||
// as `g = F c' Then basic_reduce with rewrite it
|
// as `g = FG c' Then basic_reduce with rewrite it
|
||||||
// as F(b & c).
|
// as FG(b & c).
|
||||||
if (opt & Reduce_Basics)
|
if (opt & Reduce_Basics)
|
||||||
{
|
{
|
||||||
f1 = basic_reduce(f2);
|
f1 = basic_reduce(f2);
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,23 @@ namespace spot
|
||||||
/// \brief Check whether a formula is eventual.
|
/// \brief Check whether a formula is eventual.
|
||||||
///
|
///
|
||||||
/// FIXME: Describe what eventual formulae are. Cite paper.
|
/// FIXME: Describe what eventual formulae are. Cite paper.
|
||||||
|
|
||||||
|
/// This comes from
|
||||||
|
/// \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_eventual(const formula* f);
|
bool is_eventual(const formula* f);
|
||||||
|
|
||||||
/// \brief Check whether a formula is universal.
|
/// \brief Check whether a formula is universal.
|
||||||
|
|
|
||||||
|
|
@ -72,41 +72,46 @@ namespace spot
|
||||||
visit(const unop* uo)
|
visit(const unop* uo)
|
||||||
{
|
{
|
||||||
const formula* f1 = uo->child();
|
const formula* f1 = uo->child();
|
||||||
switch (uo->op())
|
if (uo->op() == unop::F)
|
||||||
{
|
{
|
||||||
case unop::Not:
|
eventual = true;
|
||||||
case unop::X:
|
|
||||||
eventual = recurse_ev(f1);
|
|
||||||
universal = recurse_un(f1);
|
universal = recurse_un(f1);
|
||||||
return;
|
return;
|
||||||
case unop::F:
|
|
||||||
eventual = true;
|
|
||||||
return;
|
|
||||||
case unop::G:
|
|
||||||
universal = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
/* Unreachable code. */
|
if (uo->op() == unop::G)
|
||||||
assert(0);
|
{
|
||||||
|
universal = true;
|
||||||
|
eventual = recurse_ev(f1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
visit(const binop* bo)
|
visit(const binop* bo)
|
||||||
{
|
{
|
||||||
const formula* f1 = bo->first();
|
const formula* f1 = bo->first();
|
||||||
|
const formula* f2 = bo->second();
|
||||||
switch (bo->op())
|
switch (bo->op())
|
||||||
{
|
{
|
||||||
case binop::Xor:
|
case binop::Xor:
|
||||||
case binop::Equiv:
|
case binop::Equiv:
|
||||||
case binop::Implies:
|
case binop::Implies:
|
||||||
|
universal = recurse_un(f1) & recurse_un(f2);
|
||||||
|
eventual = recurse_ev(f1) & recurse_ev(f2);
|
||||||
return;
|
return;
|
||||||
case binop::U:
|
case binop::U:
|
||||||
if (f1 == constant::true_instance())
|
universal = recurse_un(f1) & recurse_un(f2);
|
||||||
|
if ((f1 == constant::true_instance()) ||
|
||||||
|
(recurse_ev(f1)))
|
||||||
eventual = true;
|
eventual = true;
|
||||||
return;
|
return;
|
||||||
case binop::R:
|
case binop::R:
|
||||||
if (f1 == constant::false_instance())
|
eventual = recurse_ev(f1) & recurse_ev(f2);
|
||||||
|
if ((f1 == constant::false_instance()))
|
||||||
|
//||
|
||||||
|
//(recurse_un(f1)))
|
||||||
universal = true;
|
universal = true;
|
||||||
|
if (!universal)
|
||||||
|
universal = recurse_un(f1) & recurse_un(f2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Unreachable code. */
|
/* Unreachable code. */
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,20 @@ namespace spot
|
||||||
{
|
{
|
||||||
namespace ltl
|
namespace ltl
|
||||||
{
|
{
|
||||||
// FIXME: Cite paper.
|
/// This comes from
|
||||||
|
/// \verbatim
|
||||||
|
/// @InProceedings{ somenzi.00.cav,
|
||||||
|
/// author = {Fabio Somenzi and Roderick Bloem},
|
||||||
|
/// title = {Efficient {B\"u}chi Automata for {LTL} Formulae},
|
||||||
|
/// booktitle = {Proceedings of the 12th International Conference on
|
||||||
|
/// Computer Aided Verification (CAV'00)},
|
||||||
|
/// pages = {247--263},
|
||||||
|
/// year = {2000},
|
||||||
|
/// volume = {1855},
|
||||||
|
/// series = {Lecture Notes in Computer Science},
|
||||||
|
/// publisher = {Springer-Verlag}
|
||||||
|
/// }
|
||||||
|
/// \endverbatim
|
||||||
|
|
||||||
/// \brief Syntactic implication.
|
/// \brief Syntactic implication.
|
||||||
bool syntactic_implication(const formula* f1, const formula* f2);
|
bool syntactic_implication(const formula* f1, const formula* f2);
|
||||||
|
|
|
||||||
|
|
@ -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
|
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
## et Marie Curie.
|
## et Marie Curie.
|
||||||
##
|
##
|
||||||
|
|
@ -41,7 +41,8 @@ tgba_HEADERS = \
|
||||||
tgbabddfactory.hh \
|
tgbabddfactory.hh \
|
||||||
tgbaexplicit.hh \
|
tgbaexplicit.hh \
|
||||||
tgbaproduct.hh \
|
tgbaproduct.hh \
|
||||||
tgbatba.hh
|
tgbatba.hh \
|
||||||
|
tgbareduc.hh
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libtgba.la
|
noinst_LTLIBRARIES = libtgba.la
|
||||||
libtgba_la_SOURCES = \
|
libtgba_la_SOURCES = \
|
||||||
|
|
@ -57,4 +58,5 @@ libtgba_la_SOURCES = \
|
||||||
tgbabddcoredata.cc \
|
tgbabddcoredata.cc \
|
||||||
tgbaexplicit.cc \
|
tgbaexplicit.cc \
|
||||||
tgbaproduct.cc \
|
tgbaproduct.cc \
|
||||||
tgbatba.cc
|
tgbatba.cc \
|
||||||
|
tgbareduc.cc
|
||||||
|
|
|
||||||
814
src/tgba/tgbareduc.cc
Normal file
814
src/tgba/tgbareduc.cc
Normal 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
160
src/tgba/tgbareduc.hh
Normal 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
|
||||||
|
|
@ -37,7 +37,8 @@ tgbaalgos_HEADERS = \
|
||||||
powerset.hh \
|
powerset.hh \
|
||||||
reachiter.hh \
|
reachiter.hh \
|
||||||
save.hh \
|
save.hh \
|
||||||
stats.hh
|
stats.hh \
|
||||||
|
reductgba_sim.hh
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libtgbaalgos.la
|
noinst_LTLIBRARIES = libtgbaalgos.la
|
||||||
libtgbaalgos_la_SOURCES = \
|
libtgbaalgos_la_SOURCES = \
|
||||||
|
|
@ -51,6 +52,8 @@ libtgbaalgos_la_SOURCES = \
|
||||||
powerset.cc \
|
powerset.cc \
|
||||||
reachiter.cc \
|
reachiter.cc \
|
||||||
save.cc \
|
save.cc \
|
||||||
stats.cc
|
stats.cc \
|
||||||
|
reductgba_sim.cc \
|
||||||
|
reductgba_sim_del.cc
|
||||||
|
|
||||||
libtgbaalgos_la_LIBADD = gtec/libgtec.la
|
libtgbaalgos_la_LIBADD = gtec/libgtec.la
|
||||||
|
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
314
src/tgbaalgos/reductgba_sim.hh
Normal file
314
src/tgbaalgos/reductgba_sim.hh
Normal file
|
|
@ -0,0 +1,314 @@
|
||||||
|
// 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_REDUC_TGBA_SIM_HH
|
||||||
|
#define SPOT_REDUC_TGBA_SIM_HH
|
||||||
|
|
||||||
|
#include "tgba/tgbareduc.hh"
|
||||||
|
#include "tgbaalgos/reachiter.hh"
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Options for reduce.
|
||||||
|
enum reduce_tgba_options
|
||||||
|
{
|
||||||
|
/// No reduction.
|
||||||
|
Reduce_None = 0,
|
||||||
|
/// Reduction using direct simulation relation.
|
||||||
|
Reduce_Dir_Sim = 1,
|
||||||
|
/// Reduction using delayed simulation relation.
|
||||||
|
Reduce_Del_Sim = 2,
|
||||||
|
/// Reduction using SCC.
|
||||||
|
Reduce_Scc = 4,
|
||||||
|
/// All reductions.
|
||||||
|
Reduce_All = -1U
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Remove some node of the automata using a simulation
|
||||||
|
/// relation.
|
||||||
|
///
|
||||||
|
/// \param a the automata to reduce.
|
||||||
|
/// \param opt a conjonction of spot::reduce_tgba_options specifying
|
||||||
|
// which optimizations to apply.
|
||||||
|
/// \return the reduced automata.
|
||||||
|
tgba* reduc_tgba_sim(const tgba* a, int opt = Reduce_All);
|
||||||
|
|
||||||
|
/// \brief Compute a direct simulation relation on state of tgba \a f.
|
||||||
|
simulation_relation* get_direct_relation_simulation(const tgba* a,
|
||||||
|
int opt = -1);
|
||||||
|
|
||||||
|
/// Compute a delayed simulation relation on state of tgba \a f.
|
||||||
|
/// FIXME : this method is incorrect !!
|
||||||
|
/// Don't use it !!
|
||||||
|
simulation_relation* get_delayed_relation_simulation(const tgba* a,
|
||||||
|
int opt = -1);
|
||||||
|
|
||||||
|
/// To free a simulation relation.
|
||||||
|
void free_relation_simulation(simulation_relation* rel);
|
||||||
|
|
||||||
|
/// Test if the initial state of a2 fair simulate this of a1.
|
||||||
|
/// Not implemented.
|
||||||
|
bool is_include(const tgba* a1, const tgba* a2);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// simulation.
|
||||||
|
|
||||||
|
class spoiler_node;
|
||||||
|
class duplicator_node;
|
||||||
|
|
||||||
|
typedef Sgi::vector<spoiler_node*> sn_v;
|
||||||
|
typedef Sgi::vector<duplicator_node*> dn_v;
|
||||||
|
typedef Sgi::vector<const state*> s_v;
|
||||||
|
|
||||||
|
/// \brief Parity game graph which compute a simulation relation.
|
||||||
|
class parity_game_graph : public tgba_reachable_iterator_breadth_first
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
parity_game_graph(const tgba* a);
|
||||||
|
virtual ~parity_game_graph();
|
||||||
|
|
||||||
|
virtual simulation_relation* get_relation() = 0;
|
||||||
|
|
||||||
|
void print(std::ostream& os);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sn_v spoiler_vertice_;
|
||||||
|
dn_v duplicator_vertice_;
|
||||||
|
s_v tgba_state_;
|
||||||
|
int nb_node_parity_game;
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void end();
|
||||||
|
void process_state(const state* s, int n, tgba_succ_iterator* si);
|
||||||
|
void process_link(int in, int out, const tgba_succ_iterator* si);
|
||||||
|
|
||||||
|
/// \brief Compute each node of the graph.
|
||||||
|
virtual void build_couple() = 0;
|
||||||
|
|
||||||
|
/// \brief Compute the link of the graph.
|
||||||
|
/// Successor of spoiler node (resp. duplicator node)
|
||||||
|
/// are duplicator node (resp. spoiler node).
|
||||||
|
virtual void build_link() = 0;
|
||||||
|
|
||||||
|
/// \brief Remove edge from spoiler to duplicator that make
|
||||||
|
/// duplicator loose.
|
||||||
|
/// Spoiler node whose still have some link, reveal
|
||||||
|
/// a direct simulation relation.
|
||||||
|
virtual void prune() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Direct simulation.
|
||||||
|
|
||||||
|
/// Spoiler node of parity game graph.
|
||||||
|
class spoiler_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spoiler_node(const state* d_node,
|
||||||
|
const state* s_node,
|
||||||
|
int num);
|
||||||
|
virtual ~spoiler_node();
|
||||||
|
|
||||||
|
void add_succ(spoiler_node* n);
|
||||||
|
void del_succ(spoiler_node* n);
|
||||||
|
virtual void add_pred(spoiler_node* n);
|
||||||
|
virtual void del_pred();
|
||||||
|
int get_nb_succ();
|
||||||
|
bool prune();
|
||||||
|
virtual bool set_win();
|
||||||
|
virtual std::string to_string(const tgba* a);
|
||||||
|
virtual std::string succ_to_string();
|
||||||
|
|
||||||
|
const state* get_spoiler_node();
|
||||||
|
const state* get_duplicator_node();
|
||||||
|
state_couple* get_pair();
|
||||||
|
|
||||||
|
bool not_win;
|
||||||
|
int num_; // for the dot display.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sn_v* lnode_succ;
|
||||||
|
sn_v* lnode_pred;
|
||||||
|
//Sgi::vector<spoiler_node*>* lnode_succ;
|
||||||
|
state_couple* sc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Duplicator node of parity game graph.
|
||||||
|
class duplicator_node : public spoiler_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
duplicator_node(const state* d_node,
|
||||||
|
const state* s_node,
|
||||||
|
bdd l,
|
||||||
|
bdd a,
|
||||||
|
int num);
|
||||||
|
virtual ~duplicator_node();
|
||||||
|
|
||||||
|
virtual bool set_win();
|
||||||
|
virtual std::string to_string(const tgba* a);
|
||||||
|
|
||||||
|
bool match(bdd l, bdd a);
|
||||||
|
bool implies(bdd l, bdd a);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bdd label_;
|
||||||
|
bdd acc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Parity game graph which compute the direct simulation relation.
|
||||||
|
class parity_game_graph_direct : public parity_game_graph
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
parity_game_graph_direct(const tgba* a);
|
||||||
|
~parity_game_graph_direct();
|
||||||
|
|
||||||
|
virtual simulation_relation* get_relation();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void build_couple();
|
||||||
|
virtual void build_link();
|
||||||
|
virtual void prune();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Delayed simulation.
|
||||||
|
|
||||||
|
/// Spoiler node of parity game graph for delayed simulation.
|
||||||
|
class spoiler_node_delayed : public spoiler_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spoiler_node_delayed(const state* d_node,
|
||||||
|
const state* s_node,
|
||||||
|
bdd a,
|
||||||
|
int num);
|
||||||
|
~spoiler_node_delayed();
|
||||||
|
|
||||||
|
/// Return true if the progress_measure has changed.
|
||||||
|
bool set_win();
|
||||||
|
bdd get_acceptance_condition_visited();
|
||||||
|
|
||||||
|
virtual std::string to_string(const tgba* a);
|
||||||
|
|
||||||
|
int get_progress_measure();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// a Bdd for retain all the acceptance condition
|
||||||
|
/// that a node has visited.
|
||||||
|
bdd acceptance_condition_visited_;
|
||||||
|
int progress_measure_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Duplicator node of parity game graph for delayed simulation.
|
||||||
|
class duplicator_node_delayed : public duplicator_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
duplicator_node_delayed(const state* d_node,
|
||||||
|
const state* s_node,
|
||||||
|
bdd l,
|
||||||
|
bdd a,
|
||||||
|
int num);
|
||||||
|
~duplicator_node_delayed();
|
||||||
|
|
||||||
|
/// Return true if the progress_measure has changed.
|
||||||
|
bool set_win();
|
||||||
|
virtual std::string to_string(const tgba* a);
|
||||||
|
|
||||||
|
bool implies_label(bdd l);
|
||||||
|
bool implies_acc(bdd a);
|
||||||
|
|
||||||
|
int get_progress_measure();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int progress_measure_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Parity game graph which compute the delayed simulation relation
|
||||||
|
/// as explain in
|
||||||
|
/// @inproceedings{ icalp2001,
|
||||||
|
/// AUTHOR = {Etessami, Thomas Wilke, Rebecca A. Schuller},
|
||||||
|
/// TITLE = {Fair Simulation Relations, Parity Games, and State Space
|
||||||
|
/// Reduction for Buchi Automata},
|
||||||
|
/// BOOKTITLE = {Automata, Languages and Programming,
|
||||||
|
/// 28th international collquium},
|
||||||
|
/// PAGES = {694--707},
|
||||||
|
/// YEAR = 2001,
|
||||||
|
/// EDITOR = {Orejas, Fernando and Spirakis, Paul G. and van Leeuwen, Jan},
|
||||||
|
/// VOLUME = 2076,
|
||||||
|
/// SERIES = {Lecture Notes in Computer Science},
|
||||||
|
/// ADDRESS = {Crete, Greece},
|
||||||
|
/// MONTH = JUL,
|
||||||
|
/// PUBLISHER = {Springer},
|
||||||
|
/// url = {citeseer.ist.psu.edu/472661.html}
|
||||||
|
/// }
|
||||||
|
|
||||||
|
class parity_game_graph_delayed : public parity_game_graph
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
parity_game_graph_delayed(const tgba* a);
|
||||||
|
~parity_game_graph_delayed();
|
||||||
|
|
||||||
|
virtual simulation_relation* get_relation();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// Vector which contain all the sub-set of the set
|
||||||
|
/// of acceptance condition.
|
||||||
|
typedef Sgi::vector<bdd> bdd_v;
|
||||||
|
bdd_v sub_set_acc_cond_;
|
||||||
|
|
||||||
|
/// Return the number of acceptance condition.
|
||||||
|
int nb_set_acc_cond();
|
||||||
|
|
||||||
|
/// Compute sub_set_acc_cond_;
|
||||||
|
void build_sub_set_acc_cond();
|
||||||
|
|
||||||
|
/// Add a duplicator node, and
|
||||||
|
/// all his successor (spoiler node) which
|
||||||
|
/// have a acceptance_condition_visited_ != bddfalse
|
||||||
|
void add_dup_node(state* ss,
|
||||||
|
state* sd,
|
||||||
|
bdd l,
|
||||||
|
bdd a);
|
||||||
|
|
||||||
|
/// \brief Compute the couple as for direct simulation,
|
||||||
|
virtual void build_couple();
|
||||||
|
virtual void build_link();
|
||||||
|
void build_recurse_successor_spoiler(spoiler_node* sn);
|
||||||
|
void build_recurse_successor_duplicator(duplicator_node* dn);
|
||||||
|
|
||||||
|
/// \brief The Jurdzinski's lifting algorithm.
|
||||||
|
void lift();
|
||||||
|
|
||||||
|
/// \brief Remove all node so as to there is no dead ends (terminal node).
|
||||||
|
virtual void prune();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
816
src/tgbaalgos/reductgba_sim_del.cc
Normal file
816
src/tgbaalgos/reductgba_sim_del.cc
Normal file
|
|
@ -0,0 +1,816 @@
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
/// Number of spoiler node with a one priority (see icalp2001).
|
||||||
|
/// The one priority is represent by a \a acceptance_condition_visited_
|
||||||
|
/// which differ of bddfalse.
|
||||||
|
/// This spoiler node are looser for the duplicator.
|
||||||
|
static int nb_spoiler_loose_;
|
||||||
|
|
||||||
|
static int nb_spoiler;
|
||||||
|
static int nb_duplicator;
|
||||||
|
|
||||||
|
//static int nb_node;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// spoiler_node_delayed
|
||||||
|
|
||||||
|
spoiler_node_delayed::spoiler_node_delayed(const state* d_node,
|
||||||
|
const state* s_node,
|
||||||
|
bdd a,
|
||||||
|
int num)
|
||||||
|
: spoiler_node(d_node, s_node, num),
|
||||||
|
acceptance_condition_visited_(a)
|
||||||
|
{
|
||||||
|
nb_spoiler++;
|
||||||
|
progress_measure_ = 0;
|
||||||
|
if (acceptance_condition_visited_ == bddfalse)
|
||||||
|
nb_spoiler_loose_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
spoiler_node_delayed::~spoiler_node_delayed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
spoiler_node_delayed::set_win()
|
||||||
|
{
|
||||||
|
// We take the max of the progress measure of the successor node
|
||||||
|
// because we are on a spoiler.
|
||||||
|
|
||||||
|
//std::cout << "spoiler_node_delayed::set_win" << std::endl;
|
||||||
|
|
||||||
|
if (lnode_succ->size() == 0)
|
||||||
|
progress_measure_ = nb_spoiler_loose_;
|
||||||
|
|
||||||
|
if (progress_measure_ >= nb_spoiler_loose_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool change;
|
||||||
|
int tmpmax = 0;
|
||||||
|
int tmp = 0;
|
||||||
|
sn_v::iterator i = lnode_succ->begin();
|
||||||
|
if (i != lnode_succ->end())
|
||||||
|
{
|
||||||
|
tmpmax =
|
||||||
|
dynamic_cast<duplicator_node_delayed*>(*i)->get_progress_measure();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
for (; i != lnode_succ->end(); ++i)
|
||||||
|
{
|
||||||
|
tmp =
|
||||||
|
dynamic_cast<duplicator_node_delayed*>(*i)->get_progress_measure();
|
||||||
|
if (tmp > tmpmax)
|
||||||
|
tmpmax = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the priority of the node is 1
|
||||||
|
// acceptance_condition_visited_ != bddfalse
|
||||||
|
// then we increment the progress measure of 1.
|
||||||
|
if (acceptance_condition_visited_ != bddfalse)
|
||||||
|
tmpmax++;
|
||||||
|
|
||||||
|
change = (progress_measure_ < tmpmax);
|
||||||
|
|
||||||
|
progress_measure_ = tmpmax;
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
spoiler_node_delayed::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(), acceptance_condition_visited_);
|
||||||
|
if (acceptance_condition_visited_ == bddfalse)
|
||||||
|
{
|
||||||
|
os << "false";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << "ACC";
|
||||||
|
}
|
||||||
|
os << ")"
|
||||||
|
<< " pm = " << progress_measure_ << "\"]"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
spoiler_node_delayed::get_acceptance_condition_visited()
|
||||||
|
{
|
||||||
|
return acceptance_condition_visited_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
spoiler_node_delayed::get_progress_measure()
|
||||||
|
{
|
||||||
|
if ((acceptance_condition_visited_ == bddfalse) &&
|
||||||
|
(progress_measure_ != (nb_spoiler_loose_ + 1)))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return progress_measure_;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// duplicator_node_delayed
|
||||||
|
|
||||||
|
duplicator_node_delayed::duplicator_node_delayed(const state* d_node,
|
||||||
|
const state* s_node,
|
||||||
|
bdd l,
|
||||||
|
bdd a,
|
||||||
|
int num)
|
||||||
|
: duplicator_node(d_node, s_node, l, a, num)
|
||||||
|
{
|
||||||
|
nb_duplicator++;
|
||||||
|
progress_measure_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicator_node_delayed::~duplicator_node_delayed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
duplicator_node_delayed::set_win()
|
||||||
|
{
|
||||||
|
// We take the min of the progress measure of the successor node
|
||||||
|
// because we are on a duplicator.
|
||||||
|
|
||||||
|
//std::cout << "duplicator_node_delayed::set_win" << std::endl;
|
||||||
|
|
||||||
|
//bool debug = true;
|
||||||
|
|
||||||
|
if (progress_measure_ == nb_spoiler_loose_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool change;
|
||||||
|
int tmpmin = 0;
|
||||||
|
int tmp = 0;
|
||||||
|
sn_v::iterator i = lnode_succ->begin();
|
||||||
|
if (i != lnode_succ->end())
|
||||||
|
{
|
||||||
|
tmpmin = dynamic_cast<spoiler_node_delayed*>(*i)->get_progress_measure();
|
||||||
|
/*
|
||||||
|
debug &= (dynamic_cast<spoiler_node_delayed*>(*i)
|
||||||
|
->get_acceptance_condition_visited()
|
||||||
|
!= bddfalse);
|
||||||
|
*/
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
for (; i != lnode_succ->end(); ++i)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
debug &= (dynamic_cast<spoiler_node_delayed*>(*i)
|
||||||
|
->get_acceptance_condition_visited()
|
||||||
|
!= bddfalse);
|
||||||
|
*/
|
||||||
|
tmp = dynamic_cast<spoiler_node_delayed*>(*i)->get_progress_measure();
|
||||||
|
if (tmp < tmpmin)
|
||||||
|
tmpmin = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (debug)
|
||||||
|
std::cout << "All successor p = 1" << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << "Not All successor p = 1" << std::endl;
|
||||||
|
*/
|
||||||
|
|
||||||
|
change = (progress_measure_ < tmpmin);
|
||||||
|
progress_measure_ = tmpmin;
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
duplicator_node_delayed::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 << ")"
|
||||||
|
<< " pm = " << progress_measure_ << "\"]"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
duplicator_node_delayed::implies_label(bdd l)
|
||||||
|
{
|
||||||
|
return ((l | !label_) == bddtrue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
duplicator_node_delayed::implies_acc(bdd a)
|
||||||
|
{
|
||||||
|
return ((a | !acc_) == bddtrue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
duplicator_node_delayed::get_progress_measure()
|
||||||
|
{
|
||||||
|
return progress_measure_;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// parity_game_graph_delayed
|
||||||
|
|
||||||
|
int
|
||||||
|
parity_game_graph_delayed::nb_set_acc_cond()
|
||||||
|
{
|
||||||
|
bdd acc, all;
|
||||||
|
acc = all = automata_->all_acceptance_conditions();
|
||||||
|
int count = 0;
|
||||||
|
while (all != bddfalse)
|
||||||
|
{
|
||||||
|
sub_set_acc_cond_.push_back(bdd_satone(all));
|
||||||
|
all -= bdd_satone(all);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::build_sub_set_acc_cond()
|
||||||
|
{
|
||||||
|
// compute the number of acceptance conditions
|
||||||
|
bdd acc, all;
|
||||||
|
acc = all = automata_->all_acceptance_conditions();
|
||||||
|
int count = 0;
|
||||||
|
while (all != bddfalse)
|
||||||
|
{
|
||||||
|
//std::cout << "add acc" << std::endl;
|
||||||
|
sub_set_acc_cond_.push_back(bdd_satone(all));
|
||||||
|
all -= bdd_satone(all);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
// sub_set_acc_cond_ contains all the acceptance condition.
|
||||||
|
// but we must have all the sub-set of acceptance condition.
|
||||||
|
// In fact we must have 2^count sub-set.
|
||||||
|
|
||||||
|
if (count == 2)
|
||||||
|
{
|
||||||
|
sub_set_acc_cond_.push_back(acc);
|
||||||
|
sub_set_acc_cond_.push_back(bddfalse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bdd_v::iterator i;
|
||||||
|
|
||||||
|
bdd_v::iterator j;
|
||||||
|
for (i = sub_set_acc_cond_.begin(); i != sub_set_acc_cond_.end(); ++i)
|
||||||
|
for (j = sub_set_acc_cond_.begin(); j != sub_set_acc_cond_.end(); ++j)
|
||||||
|
sub_set_acc_cond_.push_back(*i | *j);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
for (i = sub_set_acc_cond_.begin(); i != sub_set_acc_cond_.end();)
|
||||||
|
{
|
||||||
|
bdd_print_acc(std::cout, automata_->get_dict(), *i);
|
||||||
|
std::cout << " // " << std::endl;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::build_couple()
|
||||||
|
{
|
||||||
|
//std::cout << "build couple" << std::endl;
|
||||||
|
|
||||||
|
nb_spoiler = 0;
|
||||||
|
nb_duplicator = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
s_v::iterator i;
|
||||||
|
for (i = tgba_state_.begin(); i != tgba_state_.end(); ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
// for each sub-set of the set of acceptance condition.
|
||||||
|
bdd_v::iterator i2;
|
||||||
|
for (i2 = sub_set_acc_cond_.begin();
|
||||||
|
i2 != sub_set_acc_cond_.end(); ++i2)
|
||||||
|
{
|
||||||
|
|
||||||
|
// spoiler node are all state couple (i,j)
|
||||||
|
// multiply by 2^(|F|)
|
||||||
|
s_v::iterator i3;
|
||||||
|
for (i3 = tgba_state_.begin();
|
||||||
|
i3 != tgba_state_.end(); ++i3)
|
||||||
|
{
|
||||||
|
//nb_spoiler++;
|
||||||
|
spoiler_node_delayed* n1
|
||||||
|
= new spoiler_node_delayed(*i,
|
||||||
|
*i3,
|
||||||
|
*i2,
|
||||||
|
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 (i3 = tgba_state_.begin();
|
||||||
|
i3 != tgba_state_.end(); ++i3)
|
||||||
|
{
|
||||||
|
si = automata_->succ_iter(*i3);
|
||||||
|
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;
|
||||||
|
Sgi::vector<couple_bdd*>::iterator i4;
|
||||||
|
for (i4 = trans->begin();
|
||||||
|
i4 != trans->end(); ++i4)
|
||||||
|
{
|
||||||
|
if ((si->current_condition() == (*i4)->first))
|
||||||
|
// We don't need the acceptance condition
|
||||||
|
//&&
|
||||||
|
//(si->current_acceptance_conditions()
|
||||||
|
//== (*i4)->second))
|
||||||
|
exist = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exist)
|
||||||
|
{
|
||||||
|
// We build all the state couple with the label p.
|
||||||
|
// multiply by 2^(|F|)
|
||||||
|
trans->push_back(p);
|
||||||
|
Sgi::vector<const state*>::iterator i5;
|
||||||
|
for (i5 = tgba_state_.begin();
|
||||||
|
i5 != tgba_state_.end(); ++i5)
|
||||||
|
{
|
||||||
|
//nb_duplicator++;
|
||||||
|
int nb = nb_node_parity_game++;
|
||||||
|
duplicator_node_delayed* n2
|
||||||
|
= new
|
||||||
|
duplicator_node_delayed(*i,
|
||||||
|
*i5,
|
||||||
|
si->
|
||||||
|
current_condition(),
|
||||||
|
*i2,
|
||||||
|
nb);
|
||||||
|
duplicator_vertice_.push_back(n2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
delete si;
|
||||||
|
}
|
||||||
|
Sgi::vector<couple_bdd*>::iterator i6;
|
||||||
|
for (i6 = trans->begin(); i6 != trans->end(); ++i6)
|
||||||
|
{
|
||||||
|
delete *i6;
|
||||||
|
}
|
||||||
|
delete trans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nb_spoiler_loose_++;
|
||||||
|
|
||||||
|
//std::cout << "spoiler node : " << nb_spoiler << std::endl;
|
||||||
|
//std::cout << "duplicator node : " << nb_duplicator << std::endl;
|
||||||
|
//std::cout << "nb_spoiler_loose_ : " << nb_spoiler_loose_ << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::build_link()
|
||||||
|
{
|
||||||
|
//std::cout << "build link" << std::endl;
|
||||||
|
int nb_ds = 0;
|
||||||
|
int nb_sd = 0;
|
||||||
|
spot::state* s = NULL;
|
||||||
|
|
||||||
|
// for each couple of (spoiler, duplicator)
|
||||||
|
sn_v::iterator i;
|
||||||
|
for (i = spoiler_vertice_.begin(); i != spoiler_vertice_.end(); ++i)
|
||||||
|
{
|
||||||
|
dn_v::iterator i2;
|
||||||
|
for (i2 = duplicator_vertice_.begin();
|
||||||
|
i2 != duplicator_vertice_.end(); ++i2)
|
||||||
|
{
|
||||||
|
|
||||||
|
// We add a link between a duplicator and a spoiler.
|
||||||
|
if ((*i2)->get_spoiler_node()->compare((*i)
|
||||||
|
->get_spoiler_node()) == 0)
|
||||||
|
{
|
||||||
|
tgba_succ_iterator* si
|
||||||
|
= automata_->succ_iter((*i2)->get_duplicator_node());
|
||||||
|
for (si->first(); !si->done(); si->next())
|
||||||
|
{
|
||||||
|
s = si->current_state();
|
||||||
|
|
||||||
|
bdd btmp2 = dynamic_cast<spoiler_node_delayed*>(*i)->
|
||||||
|
get_acceptance_condition_visited();
|
||||||
|
bdd btmp = btmp2 - si->current_acceptance_conditions();
|
||||||
|
|
||||||
|
//if ((s->compare((*i)->get_duplicator_node()) == 0) &&
|
||||||
|
//dynamic_cast<duplicator_node_delayed*>(*i2)->
|
||||||
|
// implies_label(si->current_condition()) &&
|
||||||
|
//(btmp == btmp2))
|
||||||
|
|
||||||
|
if ((s->compare((*i)->get_duplicator_node()) == 0) &&
|
||||||
|
dynamic_cast<duplicator_node_delayed*>(*i2)->
|
||||||
|
implies_label(si->current_condition()) &&
|
||||||
|
(dynamic_cast<spoiler_node_delayed*>(*i)->
|
||||||
|
get_acceptance_condition_visited() != bddfalse))
|
||||||
|
{
|
||||||
|
//std::cout << "add duplicator -> spoiler" << std::endl;
|
||||||
|
(*i2)->add_succ(*i);
|
||||||
|
(*i)->add_pred(*i2);
|
||||||
|
nb_ds++;
|
||||||
|
}
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
delete si;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We add a link between a spoiler and a duplicator.
|
||||||
|
if ((*i2)->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();
|
||||||
|
|
||||||
|
bdd btmp = si->current_acceptance_conditions() |
|
||||||
|
dynamic_cast<spoiler_node_delayed*>(*i)->
|
||||||
|
get_acceptance_condition_visited();
|
||||||
|
if ((s->compare((*i2)->get_spoiler_node()) == 0) &&
|
||||||
|
(*i2)->match(si->current_condition(), btmp))
|
||||||
|
{
|
||||||
|
//std::cout << "add spoiler -> duplicator" << std::endl;
|
||||||
|
(*i)->add_succ(*i2);
|
||||||
|
(*i2)->add_pred(*i);
|
||||||
|
nb_sd++;
|
||||||
|
}
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
delete si;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// We build only node which are reachable
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::build_couple()
|
||||||
|
{
|
||||||
|
// We build only some "basic" spoiler node.
|
||||||
|
|
||||||
|
s_v::iterator i;
|
||||||
|
for (i = tgba_state_.begin(); i != tgba_state_.end(); ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
// spoiler node are all state couple (i,j)
|
||||||
|
s_v::iterator i2;
|
||||||
|
for (i2 = tgba_state_.begin();
|
||||||
|
i2 != tgba_state_.end(); ++i2)
|
||||||
|
{
|
||||||
|
std::cout << "add spoiler node" << std::endl;
|
||||||
|
nb_spoiler++;
|
||||||
|
spoiler_node_delayed* n1
|
||||||
|
= new spoiler_node_delayed(*i, *i2,
|
||||||
|
bddfalse,
|
||||||
|
nb_node_parity_game++);
|
||||||
|
spoiler_vertice_.push_back(n1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::build_link()
|
||||||
|
{
|
||||||
|
// We create when it's possible a duplicator node
|
||||||
|
// and recursively his successor.
|
||||||
|
|
||||||
|
spot::state* s1 = NULL;
|
||||||
|
bool exist_pred = false;
|
||||||
|
|
||||||
|
sn_v::iterator i1;
|
||||||
|
for (i1 = spoiler_vertice_.begin(); i1 != spoiler_vertice_.end(); ++i1)
|
||||||
|
{
|
||||||
|
exist_pred = false;
|
||||||
|
// We check if there is a predecessor only if the duplicator
|
||||||
|
// is the initial state.
|
||||||
|
s1 = automata_->get_init_state();
|
||||||
|
if (s1->compare((*i1)->get_duplicator_node()) == 0)
|
||||||
|
{
|
||||||
|
tgba_succ_iterator* si;
|
||||||
|
s_v::iterator i2;
|
||||||
|
spot::state* s2 = NULL;
|
||||||
|
for (i2 = tgba_state_.begin();
|
||||||
|
i2 != tgba_state_.end(); ++i2)
|
||||||
|
{
|
||||||
|
si = automata_->succ_iter(*i2);
|
||||||
|
s2 = si->current_state();
|
||||||
|
if (s2->compare(s1) == 0)
|
||||||
|
exist_pred = true;
|
||||||
|
delete s2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
exist_pred = true;
|
||||||
|
delete s1;
|
||||||
|
|
||||||
|
if (!exist_pred)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We add a link between a spoiler and a (new) duplicator.
|
||||||
|
// The acc of the duplicator must contains the
|
||||||
|
// acceptance_condition_visited_ of the spoiler.
|
||||||
|
build_recurse_successor_spoiler(*i1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::build_recurse_successor_spoiler(spoiler_node* sn)
|
||||||
|
{
|
||||||
|
tgba_succ_iterator* si = automata_->succ_iter(sn->get_spoiler_node());
|
||||||
|
|
||||||
|
for (si->first(); !si->done(); si->next())
|
||||||
|
{
|
||||||
|
bdd btmp = si->current_acceptance_conditions() |
|
||||||
|
dynamic_cast<spoiler_node_delayed*>(sn)->
|
||||||
|
get_acceptance_condition_visited();
|
||||||
|
|
||||||
|
s_v::iterator i1;
|
||||||
|
state* s;
|
||||||
|
for (i1 = tgba_state_.begin();
|
||||||
|
i1 != tgba_state_.end(); ++i1)
|
||||||
|
{
|
||||||
|
s = si->current_state();
|
||||||
|
if (s->compare(*i1) == 0)
|
||||||
|
{
|
||||||
|
duplicator_node_delayed* dn
|
||||||
|
= new duplicator_node_delayed(*i1,
|
||||||
|
sn->get_duplicator_node(),
|
||||||
|
si->current_condition(),
|
||||||
|
btmp,
|
||||||
|
nb_node_parity_game++);
|
||||||
|
duplicator_vertice_.push_back(dn);
|
||||||
|
|
||||||
|
sn->add_succ(dn);
|
||||||
|
(dn)->add_pred(sn);
|
||||||
|
|
||||||
|
build_recurse_successor_duplicator(dn);
|
||||||
|
}
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete si;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::
|
||||||
|
build_recurse_successor_duplicator(duplicator_node* dn)
|
||||||
|
{
|
||||||
|
tgba_succ_iterator* si = automata_->succ_iter(sn->get_spoiler_node());
|
||||||
|
|
||||||
|
for (si->first(); !si->done(); si->next())
|
||||||
|
{
|
||||||
|
bdd btmp =
|
||||||
|
dynamic_cast<spoiler_node_delayed*>(sn)->
|
||||||
|
get_acceptance_condition_visited();
|
||||||
|
bdd btmp2 = btmp - si->current_acceptance_conditions();
|
||||||
|
|
||||||
|
s_v::iterator i1;
|
||||||
|
state* s;
|
||||||
|
for (i1 = tgba_state_.begin();
|
||||||
|
i1 != tgba_state_.end(); ++i1)
|
||||||
|
{
|
||||||
|
s = si->current_state();
|
||||||
|
if (s->compare(*i1) == 0)
|
||||||
|
{
|
||||||
|
spoiler_node_delayed* sn
|
||||||
|
= new spoiler_node_delayed(sn->get_spoiler_node(),
|
||||||
|
*i1,
|
||||||
|
bddtmp2,
|
||||||
|
nb_node_parity_game++);
|
||||||
|
spoiler_vertice_.push_back(n1);
|
||||||
|
|
||||||
|
sn->add_succ(dn);
|
||||||
|
(dn)->add_pred(sn);
|
||||||
|
|
||||||
|
build_recurse_successor_spoiler(sn);
|
||||||
|
|
||||||
|
}
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete si;
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::add_dup_node(state*,
|
||||||
|
state*,
|
||||||
|
bdd,
|
||||||
|
bdd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::prune()
|
||||||
|
{
|
||||||
|
|
||||||
|
bool change = true;
|
||||||
|
|
||||||
|
while (change)
|
||||||
|
{
|
||||||
|
change = false;
|
||||||
|
for (Sgi::vector<duplicator_node*>::iterator i
|
||||||
|
= duplicator_vertice_.begin();
|
||||||
|
i != duplicator_vertice_.end();)
|
||||||
|
{
|
||||||
|
if ((*i)->get_nb_succ() == 0)
|
||||||
|
{
|
||||||
|
(*i)->del_pred();
|
||||||
|
delete *i;
|
||||||
|
i = duplicator_vertice_.erase(i);
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
for (Sgi::vector<spoiler_node*>::iterator i
|
||||||
|
= spoiler_vertice_.begin();
|
||||||
|
i != spoiler_vertice_.end();)
|
||||||
|
{
|
||||||
|
if ((*i)->get_nb_succ() == 0)
|
||||||
|
{
|
||||||
|
(*i)->del_pred();
|
||||||
|
delete *i;
|
||||||
|
i = spoiler_vertice_.erase(i);
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parity_game_graph_delayed::lift()
|
||||||
|
{
|
||||||
|
// Jurdzinski's algorithm
|
||||||
|
//int iter = 0;
|
||||||
|
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_delayed::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 (dynamic_cast<spoiler_node_delayed*>(*i)->get_progress_measure()
|
||||||
|
< nb_spoiler_loose_)
|
||||||
|
{
|
||||||
|
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_delayed::~parity_game_graph_delayed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
parity_game_graph_delayed::parity_game_graph_delayed(const tgba* a)
|
||||||
|
: parity_game_graph(a)
|
||||||
|
{
|
||||||
|
nb_spoiler_loose_ = 0;
|
||||||
|
/*
|
||||||
|
if (this->nb_set_acc_cond() > 2)
|
||||||
|
return;
|
||||||
|
this->build_sub_set_acc_cond();
|
||||||
|
*/
|
||||||
|
this->build_couple();
|
||||||
|
this->build_link();
|
||||||
|
this->prune();
|
||||||
|
this->lift();
|
||||||
|
//this->print(std::cout);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
simulation_relation*
|
||||||
|
get_delayed_relation_simulation(const tgba* f, int opt)
|
||||||
|
{
|
||||||
|
/// FIXME : this method is incorrect !!
|
||||||
|
/// Don't use it !!
|
||||||
|
parity_game_graph_delayed* G = new parity_game_graph_delayed(f);
|
||||||
|
simulation_relation* rel = G->get_relation();
|
||||||
|
if (opt == 1)
|
||||||
|
G->print(std::cout);
|
||||||
|
delete G;
|
||||||
|
return rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -38,6 +38,7 @@ check_PROGRAMS = \
|
||||||
mixprod \
|
mixprod \
|
||||||
powerset \
|
powerset \
|
||||||
readsave \
|
readsave \
|
||||||
|
reductgba \
|
||||||
tgbaread \
|
tgbaread \
|
||||||
tripprod
|
tripprod
|
||||||
|
|
||||||
|
|
@ -53,12 +54,14 @@ ltlprod_SOURCES = ltlprod.cc
|
||||||
mixprod_SOURCES = mixprod.cc
|
mixprod_SOURCES = mixprod.cc
|
||||||
powerset_SOURCES = powerset.cc
|
powerset_SOURCES = powerset.cc
|
||||||
readsave_SOURCES = readsave.cc
|
readsave_SOURCES = readsave.cc
|
||||||
|
reductgba_SOURCES = reductgba.cc
|
||||||
tgbaread_SOURCES = tgbaread.cc
|
tgbaread_SOURCES = tgbaread.cc
|
||||||
tripprod_SOURCES = tripprod.cc
|
tripprod_SOURCES = tripprod.cc
|
||||||
|
|
||||||
# Keep this sorted by STRENGTH. Test basic things first,
|
# Keep this sorted by STRENGTH. Test basic things first,
|
||||||
# because such failures will be easier to diagnose and fix.
|
# because such failures will be easier to diagnose and fix.
|
||||||
TESTS = \
|
TESTS = \
|
||||||
|
reductgba.test \
|
||||||
explicit.test \
|
explicit.test \
|
||||||
tgbaread.test \
|
tgbaread.test \
|
||||||
readsave.test \
|
readsave.test \
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "ltlvisit/destroy.hh"
|
#include "ltlvisit/destroy.hh"
|
||||||
#include "ltlvisit/reducform.hh"
|
#include "ltlvisit/reducform.hh"
|
||||||
|
#include "ltlvisit/tostring.hh"
|
||||||
#include "ltlast/allnodes.hh"
|
#include "ltlast/allnodes.hh"
|
||||||
#include "ltlparse/public.hh"
|
#include "ltlparse/public.hh"
|
||||||
#include "tgbaalgos/ltl2tgba_lacim.hh"
|
#include "tgbaalgos/ltl2tgba_lacim.hh"
|
||||||
|
|
@ -40,6 +41,8 @@
|
||||||
#include "tgbaalgos/dupexp.hh"
|
#include "tgbaalgos/dupexp.hh"
|
||||||
#include "tgbaalgos/neverclaim.hh"
|
#include "tgbaalgos/neverclaim.hh"
|
||||||
|
|
||||||
|
#include "tgbaalgos/reductgba_sim.hh"
|
||||||
|
|
||||||
void
|
void
|
||||||
syntax(char* prog)
|
syntax(char* prog)
|
||||||
{
|
{
|
||||||
|
|
@ -83,6 +86,7 @@ syntax(char* prog)
|
||||||
<< " -r3 reduce formula using implication between "
|
<< " -r3 reduce formula using implication between "
|
||||||
<< "sub-formulae" << std::endl
|
<< "sub-formulae" << std::endl
|
||||||
<< " -r4 reduce formula using all rules" << std::endl
|
<< " -r4 reduce formula using all rules" << std::endl
|
||||||
|
<< " -rd display the reduce formula" << std::endl
|
||||||
<< " -R same as -r, but as a set" << std::endl
|
<< " -R same as -r, but as a set" << std::endl
|
||||||
<< " -s convert to explicit automata, and number states "
|
<< " -s convert to explicit automata, and number states "
|
||||||
<< "in DFS order" << std::endl
|
<< "in DFS order" << std::endl
|
||||||
|
|
@ -98,7 +102,17 @@ syntax(char* prog)
|
||||||
<< " -X do not compute an automaton, read it from a file"
|
<< " -X do not compute an automaton, read it from a file"
|
||||||
<< std::endl
|
<< std::endl
|
||||||
<< " -y do not merge states with same symbolic representation "
|
<< " -y do not merge states with same symbolic representation "
|
||||||
<< "(implies -f)" << std::endl;
|
<< "(implies -f)" << std::endl
|
||||||
|
<< " -R1 use direct simulation to reduce the automata "
|
||||||
|
<< "(implies -L)"
|
||||||
|
<< std::endl
|
||||||
|
<< " -R2 use delayed simulation to reduce the automata, incorrect"
|
||||||
|
<< "(implies -L)"
|
||||||
|
<< std::endl
|
||||||
|
<< " -R3 use SCC to reduce the automata"
|
||||||
|
<< std::endl
|
||||||
|
<< " -Rd to display simulation relation"
|
||||||
|
<< std::endl;
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,7 +134,10 @@ main(int argc, char** argv)
|
||||||
bool magic_many = false;
|
bool magic_many = false;
|
||||||
bool expect_counter_example = false;
|
bool expect_counter_example = false;
|
||||||
bool from_file = false;
|
bool from_file = false;
|
||||||
|
int reduc_aut = spot::Reduce_None;
|
||||||
int redopt = spot::ltl::Reduce_None;
|
int redopt = spot::ltl::Reduce_None;
|
||||||
|
bool display_reduce_form = false;
|
||||||
|
bool display_rel_sim = false;
|
||||||
bool post_branching = false;
|
bool post_branching = false;
|
||||||
bool fair_loop_approx = false;
|
bool fair_loop_approx = false;
|
||||||
|
|
||||||
|
|
@ -226,11 +243,11 @@ main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[formula_index], "-r2"))
|
else if (!strcmp(argv[formula_index], "-r2"))
|
||||||
{
|
{
|
||||||
redopt |= spot::ltl::Reduce_Syntactic_Implications;
|
redopt |= spot::ltl::Reduce_Eventuality_And_Universality;
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[formula_index], "-r3"))
|
else if (!strcmp(argv[formula_index], "-r3"))
|
||||||
{
|
{
|
||||||
redopt |= spot::ltl::Reduce_Eventuality_And_Universality;
|
redopt |= spot::ltl::Reduce_Syntactic_Implications;
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[formula_index], "-r4"))
|
else if (!strcmp(argv[formula_index], "-r4"))
|
||||||
{
|
{
|
||||||
|
|
@ -274,6 +291,28 @@ main(int argc, char** argv)
|
||||||
fm_opt = true;
|
fm_opt = true;
|
||||||
fm_symb_merge_opt = false;
|
fm_symb_merge_opt = false;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-R1"))
|
||||||
|
{
|
||||||
|
reduc_aut |= spot::Reduce_Dir_Sim;
|
||||||
|
fair_loop_approx = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-R2"))
|
||||||
|
{
|
||||||
|
reduc_aut |= spot::Reduce_Del_Sim;
|
||||||
|
fair_loop_approx = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-R3"))
|
||||||
|
{
|
||||||
|
reduc_aut |= spot::Reduce_Scc;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-rd"))
|
||||||
|
{
|
||||||
|
display_reduce_form = true;
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[formula_index], "-Rd"))
|
||||||
|
{
|
||||||
|
display_rel_sim = true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|
@ -341,6 +380,8 @@ main(int argc, char** argv)
|
||||||
spot::ltl::formula* t = spot::ltl::reduce(f, redopt);
|
spot::ltl::formula* t = spot::ltl::reduce(f, redopt);
|
||||||
spot::ltl::destroy(f);
|
spot::ltl::destroy(f);
|
||||||
f = t;
|
f = t;
|
||||||
|
if (display_reduce_form)
|
||||||
|
std::cout << spot::ltl::to_string(f) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fm_opt)
|
if (fm_opt)
|
||||||
|
|
@ -352,6 +393,46 @@ main(int argc, char** argv)
|
||||||
to_free = a = concrete = spot::ltl_to_tgba_lacim(f, dict);
|
to_free = a = concrete = spot::ltl_to_tgba_lacim(f, dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
spot::tgba* aut_red = 0;
|
||||||
|
if (reduc_aut != spot::Reduce_None)
|
||||||
|
a = aut_red = spot::reduc_tgba_sim(a, reduc_aut);
|
||||||
|
*/
|
||||||
|
|
||||||
|
spot::tgba_reduc* aut_red = 0;
|
||||||
|
if (reduc_aut != spot::Reduce_None)
|
||||||
|
{
|
||||||
|
a = aut_red = new spot::tgba_reduc(a);
|
||||||
|
if ((reduc_aut & spot::Reduce_Dir_Sim) ||
|
||||||
|
(reduc_aut & spot::Reduce_Del_Sim))
|
||||||
|
{
|
||||||
|
spot::simulation_relation* rel;
|
||||||
|
if (reduc_aut & spot::Reduce_Dir_Sim)
|
||||||
|
rel = spot::get_direct_relation_simulation(a);
|
||||||
|
else if (reduc_aut & spot::Reduce_Del_Sim)
|
||||||
|
rel = spot::get_delayed_relation_simulation(a, 1);
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
if (display_rel_sim)
|
||||||
|
aut_red->display_rel_sim(rel, std::cout);
|
||||||
|
|
||||||
|
if (reduc_aut & spot::Reduce_Dir_Sim)
|
||||||
|
aut_red->prune_automata(rel);
|
||||||
|
else if (reduc_aut & spot::Reduce_Del_Sim)
|
||||||
|
aut_red->quotient_state(rel);
|
||||||
|
else
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
spot::free_relation_simulation(rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reduc_aut & spot::Reduce_Scc)
|
||||||
|
{
|
||||||
|
aut_red->prune_scc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spot::tgba_tba_proxy* degeneralized = 0;
|
spot::tgba_tba_proxy* degeneralized = 0;
|
||||||
if (degeneralize_opt)
|
if (degeneralize_opt)
|
||||||
a = degeneralized = new spot::tgba_tba_proxy(a);
|
a = degeneralized = new spot::tgba_tba_proxy(a);
|
||||||
|
|
@ -477,6 +558,8 @@ main(int argc, char** argv)
|
||||||
delete expl;
|
delete expl;
|
||||||
if (degeneralize_opt)
|
if (degeneralize_opt)
|
||||||
delete degeneralized;
|
delete degeneralized;
|
||||||
|
if (aut_red)
|
||||||
|
delete aut_red;
|
||||||
|
|
||||||
delete to_free;
|
delete to_free;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,15 @@ set -e
|
||||||
cat > config <<EOF
|
cat > config <<EOF
|
||||||
Algorithm
|
Algorithm
|
||||||
{
|
{
|
||||||
Name = "Spot (Couvreur -- LaCIM), reduction of formula"
|
Name = "Spot (Couvreur -- LaCIM)"
|
||||||
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r4 -F -t'"
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -F -t'"
|
||||||
Enabled = yes
|
Enabled = yes
|
||||||
}
|
}
|
||||||
|
|
||||||
Algorithm
|
Algorithm
|
||||||
{
|
{
|
||||||
Name = "Spot (Couvreur -- LaCIM)"
|
Name = "Spot (Couvreur -- LaCIM), reduction of formula"
|
||||||
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -F -t'"
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r4 -F -t'"
|
||||||
Enabled = yes
|
Enabled = yes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,6 +63,48 @@ Algorithm
|
||||||
Enabled = yes
|
Enabled = yes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), basic reduction of formula"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r1 -F -f -t'"
|
||||||
|
Enabled = no
|
||||||
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), reduction of formula using class of formula"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r2 -F -f -t'"
|
||||||
|
Enabled = no
|
||||||
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), reduction of formula using implies relation"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r3 -F -f -t'"
|
||||||
|
Enabled = no
|
||||||
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), reduction of formula (pre reduction)"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r4 -F -f -t'"
|
||||||
|
Enabled = yes
|
||||||
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), post reduction"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -R1 -R2 -F -f -t'"
|
||||||
|
Enabled = yes
|
||||||
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), pre + post reduction"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r4 -R1 -R2 -F -f -t'"
|
||||||
|
Enabled = yes
|
||||||
|
}
|
||||||
|
|
||||||
Algorithm
|
Algorithm
|
||||||
{
|
{
|
||||||
Name = "Spot (Couvreur -- FM), without symb_merge"
|
Name = "Spot (Couvreur -- FM), without symb_merge"
|
||||||
|
|
@ -91,6 +133,13 @@ Algorithm
|
||||||
Enabled = no
|
Enabled = no
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
{
|
||||||
|
Name = "Spot (Couvreur -- FM), reduction of formula, fake"
|
||||||
|
Path = "${LBTT_TRANSLATE} --spot './ltl2tgba -r4 -F -f -T'"
|
||||||
|
Enabled = no
|
||||||
|
}
|
||||||
|
|
||||||
Algorithm
|
Algorithm
|
||||||
{
|
{
|
||||||
Name = "Spot (Couvreur -- FM), without symb_merge, fake"
|
Name = "Spot (Couvreur -- FM), without symb_merge, fake"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue