* 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
|
|
@ -23,7 +23,9 @@
|
|||
#include "ltlast/allnodes.hh"
|
||||
#include <cassert>
|
||||
|
||||
#include "ltlvisit/clone.hh"
|
||||
#include "ltlvisit/destroy.hh"
|
||||
#include "ltlvisit/dump.hh"
|
||||
|
||||
namespace spot
|
||||
{
|
||||
|
|
@ -85,6 +87,33 @@ namespace spot
|
|||
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
|
||||
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)
|
||||
mo = dynamic_cast<multop*>(result_);
|
||||
if (mo && mo->size() == 2)
|
||||
if (mo)
|
||||
{
|
||||
// FIXME: This is incomplete. It should be done for
|
||||
// multops of any size.
|
||||
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_ = param_case(mo, unop::X, mo->op());
|
||||
return;
|
||||
}
|
||||
|
||||
result_ = unop::instance(unop::X, result_);
|
||||
|
|
@ -161,34 +170,12 @@ namespace spot
|
|||
|
||||
// F(f1 & GF(f2)) = F(f1) & GF(F2)
|
||||
mo = dynamic_cast<multop*>(result_);
|
||||
if (mo && mo->op() == multop::And
|
||||
// FIXME: This is incomplete. It should be done for
|
||||
// "And"s of any size.
|
||||
&& mo->size() == 2)
|
||||
if (mo && mo->op() == multop::And)
|
||||
{
|
||||
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_ = param_case(mo, unop::F, multop::And);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
result_ = unop::instance(unop::F, result_);
|
||||
return;
|
||||
|
||||
|
|
@ -222,31 +209,10 @@ namespace spot
|
|||
|
||||
// G(f1 | GF(f2)) = G(f1) | GF(F2)
|
||||
mo = dynamic_cast<multop*>(result_);
|
||||
if (mo && mo->op() == multop::Or
|
||||
// FIXME: This is incomplete. It should be done for
|
||||
// "Or"s of any size.
|
||||
&& mo->size() == 2)
|
||||
if (mo && mo->op() == multop::Or)
|
||||
{
|
||||
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_ = param_case(mo, unop::G, multop::Or);
|
||||
return;
|
||||
}
|
||||
|
||||
result_ = unop::instance(unop::G, result_);
|
||||
|
|
@ -385,17 +351,17 @@ namespace spot
|
|||
if (uo && uo->op() == unop::X)
|
||||
{
|
||||
// Xa & Xb = X(a & b)
|
||||
tmpX->push_back(basic_reduce(uo->child()));
|
||||
tmpX->push_back(clone(uo->child()));
|
||||
}
|
||||
else if (is_FG(*i))
|
||||
{
|
||||
// FG(a) & FG(b) = FG(a & b)
|
||||
unop* uo2 = dynamic_cast<unop*>(uo->child());
|
||||
tmpFG->push_back(basic_reduce(uo2->child()));
|
||||
tmpFG->push_back(clone(uo2->child()));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpOther->push_back(basic_reduce(*i));
|
||||
tmpOther->push_back(clone(*i));
|
||||
}
|
||||
}
|
||||
else if (bo)
|
||||
|
|
@ -414,7 +380,7 @@ namespace spot
|
|||
&& ftmp == bo2->second())
|
||||
{
|
||||
tmpUright
|
||||
->push_back(basic_reduce(bo2->first()));
|
||||
->push_back(clone(bo2->first()));
|
||||
if (j != i)
|
||||
{
|
||||
destroy(*j);
|
||||
|
|
@ -428,7 +394,7 @@ namespace spot
|
|||
instance(multop::
|
||||
And,
|
||||
tmpUright),
|
||||
basic_reduce(ftmp)));
|
||||
clone(ftmp)));
|
||||
}
|
||||
else if (bo->op() == binop::R)
|
||||
{
|
||||
|
|
@ -444,7 +410,7 @@ namespace spot
|
|||
&& ftmp == bo2->first())
|
||||
{
|
||||
tmpRright
|
||||
->push_back(basic_reduce(bo2->second()));
|
||||
->push_back(clone(bo2->second()));
|
||||
if (j != i)
|
||||
{
|
||||
destroy(*j);
|
||||
|
|
@ -454,19 +420,19 @@ namespace spot
|
|||
}
|
||||
tmpR
|
||||
->push_back(binop::instance(binop::R,
|
||||
basic_reduce(ftmp),
|
||||
clone(ftmp),
|
||||
multop::
|
||||
instance(multop::And,
|
||||
tmpRright)));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpOther->push_back(basic_reduce(*i));
|
||||
tmpOther->push_back(clone(*i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpOther->push_back(basic_reduce(*i));
|
||||
tmpOther->push_back(clone(*i));
|
||||
}
|
||||
destroy(*i);
|
||||
}
|
||||
|
|
@ -489,17 +455,17 @@ namespace spot
|
|||
if (uo && uo->op() == unop::X)
|
||||
{
|
||||
// Xa | Xb = X(a | b)
|
||||
tmpX->push_back(basic_reduce(uo->child()));
|
||||
tmpX->push_back(clone(uo->child()));
|
||||
}
|
||||
else if (is_GF(*i))
|
||||
{
|
||||
// GF(a) | GF(b) = GF(a | b)
|
||||
unop* uo2 = dynamic_cast<unop*>(uo->child());
|
||||
tmpGF->push_back(basic_reduce(uo2->child()));
|
||||
tmpGF->push_back(clone(uo2->child()));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpOther->push_back(basic_reduce(*i));
|
||||
tmpOther->push_back(clone(*i));
|
||||
}
|
||||
}
|
||||
else if (bo)
|
||||
|
|
@ -518,7 +484,7 @@ namespace spot
|
|||
&& ftmp == bo2->first())
|
||||
{
|
||||
tmpUright
|
||||
->push_back(basic_reduce(bo2->second()));
|
||||
->push_back(clone(bo2->second()));
|
||||
if (j != i)
|
||||
{
|
||||
destroy(*j);
|
||||
|
|
@ -527,7 +493,7 @@ namespace spot
|
|||
}
|
||||
}
|
||||
tmpU->push_back(binop::instance(binop::U,
|
||||
basic_reduce(ftmp),
|
||||
clone(ftmp),
|
||||
multop::
|
||||
instance(multop::Or,
|
||||
tmpUright)));
|
||||
|
|
@ -546,7 +512,7 @@ namespace spot
|
|||
&& ftmp == bo2->second())
|
||||
{
|
||||
tmpRright
|
||||
->push_back(basic_reduce(bo->first()));
|
||||
->push_back(clone(bo2->first()));
|
||||
if (j != i)
|
||||
{
|
||||
destroy(*j);
|
||||
|
|
@ -559,16 +525,16 @@ namespace spot
|
|||
multop::
|
||||
instance(multop::Or,
|
||||
tmpRright),
|
||||
basic_reduce(ftmp)));
|
||||
clone(ftmp)));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpOther->push_back(basic_reduce(*i));
|
||||
tmpOther->push_back(clone(*i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpOther->push_back(basic_reduce(*i));
|
||||
tmpOther->push_back(clone(*i));
|
||||
}
|
||||
destroy(*i);
|
||||
}
|
||||
|
|
@ -582,23 +548,27 @@ namespace spot
|
|||
res->clear();
|
||||
delete res;
|
||||
|
||||
if (tmpX->size())
|
||||
|
||||
if (tmpX && tmpX->size())
|
||||
tmpOther->push_back(unop::instance(unop::X,
|
||||
multop::instance(mo->op(),
|
||||
tmpX)));
|
||||
else
|
||||
else if (tmpX && !tmpX->size())
|
||||
delete tmpX;
|
||||
|
||||
if (tmpU->size())
|
||||
|
||||
if (tmpU && tmpU->size())
|
||||
tmpOther->push_back(multop::instance(mo->op(), tmpU));
|
||||
else
|
||||
else if (tmpU && !tmpU->size())
|
||||
delete tmpU;
|
||||
|
||||
if (tmpR->size())
|
||||
|
||||
if (tmpR && tmpR->size())
|
||||
tmpOther->push_back(multop::instance(mo->op(), tmpR));
|
||||
else
|
||||
else if (tmpR && !tmpR->size())
|
||||
delete tmpR;
|
||||
|
||||
|
||||
if (tmpGF && tmpGF->size())
|
||||
{
|
||||
formula* ftmp
|
||||
|
|
@ -608,6 +578,10 @@ namespace spot
|
|||
tmpGF)));
|
||||
tmpOther->push_back(ftmp);
|
||||
}
|
||||
else if (tmpGF && !tmpGF->size())
|
||||
delete tmpGF;
|
||||
|
||||
|
||||
if (tmpFG && tmpFG->size())
|
||||
{
|
||||
formula* ftmp
|
||||
|
|
@ -617,6 +591,9 @@ namespace spot
|
|||
tmpFG)));
|
||||
tmpOther->push_back(ftmp);
|
||||
}
|
||||
else if (tmpFG && !tmpFG->size())
|
||||
delete tmpFG;
|
||||
|
||||
|
||||
result_ = multop::instance(op, tmpOther);
|
||||
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ namespace spot
|
|||
destroy(f2);
|
||||
f2 = f1;
|
||||
}
|
||||
|
||||
if (opt & (Reduce_Syntactic_Implications
|
||||
| Reduce_Eventuality_And_Universality))
|
||||
{
|
||||
|
|
@ -322,9 +323,9 @@ namespace spot
|
|||
|
||||
// Run basic_reduce again.
|
||||
//
|
||||
// Consider `F b & g' were g is an eventual formula rewritten
|
||||
// as `g = F c' Then basic_reduce with rewrite it
|
||||
// as F(b & c).
|
||||
// Consider `FG b & g' were g is an eventual formula rewritten
|
||||
// as `g = FG c' Then basic_reduce with rewrite it
|
||||
// as FG(b & c).
|
||||
if (opt & Reduce_Basics)
|
||||
{
|
||||
f1 = basic_reduce(f2);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,23 @@ namespace spot
|
|||
/// \brief Check whether a formula is eventual.
|
||||
///
|
||||
/// 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);
|
||||
|
||||
/// \brief Check whether a formula is universal.
|
||||
|
|
|
|||
|
|
@ -72,41 +72,46 @@ namespace spot
|
|||
visit(const unop* uo)
|
||||
{
|
||||
const formula* f1 = uo->child();
|
||||
switch (uo->op())
|
||||
if (uo->op() == unop::F)
|
||||
{
|
||||
case unop::Not:
|
||||
case unop::X:
|
||||
eventual = recurse_ev(f1);
|
||||
eventual = true;
|
||||
universal = recurse_un(f1);
|
||||
return;
|
||||
case unop::F:
|
||||
eventual = true;
|
||||
return;
|
||||
case unop::G:
|
||||
universal = true;
|
||||
return;
|
||||
}
|
||||
/* Unreachable code. */
|
||||
assert(0);
|
||||
if (uo->op() == unop::G)
|
||||
{
|
||||
universal = true;
|
||||
eventual = recurse_ev(f1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visit(const binop* bo)
|
||||
{
|
||||
const formula* f1 = bo->first();
|
||||
const formula* f2 = bo->second();
|
||||
switch (bo->op())
|
||||
{
|
||||
case binop::Xor:
|
||||
case binop::Equiv:
|
||||
case binop::Implies:
|
||||
universal = recurse_un(f1) & recurse_un(f2);
|
||||
eventual = recurse_ev(f1) & recurse_ev(f2);
|
||||
return;
|
||||
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;
|
||||
return;
|
||||
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;
|
||||
if (!universal)
|
||||
universal = recurse_un(f1) & recurse_un(f2);
|
||||
return;
|
||||
}
|
||||
/* Unreachable code. */
|
||||
|
|
|
|||
|
|
@ -28,7 +28,20 @@ namespace spot
|
|||
{
|
||||
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.
|
||||
bool syntactic_implication(const formula* f1, const formula* f2);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue