* iface/gspn/gspn.cc, src/ltlvisit/basicreduce.cc,

src/ltlvisit/destroy.cc, src/ltlvisit/dotty.cc,
src/ltlvisit/dump.cc, src/ltlvisit/length.cc,
src/ltlvisit/nenoform.cc, src/ltlvisit/reduce.cc,
src/ltlvisit/syntimpl.cc, src/ltlvisit/tostring.cc,
src/tgba/formula2bdd.cc, src/tgba/tgbabddconcreteproduct.cc,
src/tgba/tgbatba.cc, src/tgbaalgos/dotty.cc,
src/tgbaalgos/dupexp.cc, src/tgbaalgos/lbtt.cc,
src/tgbaalgos/ltl2tgba_lacim.cc, src/tgbaalgos/neverclaim.cc,
src/tgbaalgos/save.cc, src/tgbaalgos/stats.cc,
src/tgbaalgos/gtec/nsheap.cc, src/tgbaalgos/gtec/nsheap.hh:
Declare private classes and helper function in anonymous namespaces.
* HACKING, src/sanity/style.test: Document and check this.
Also check for trailing { after namespace or class.
* src/ltlast/predecl.hh, src/ltlast/visitor.hh,
src/tgba/tgbareduc.hh: Fix trailing {.
This commit is contained in:
Alexandre Duret-Lutz 2004-10-18 13:56:31 +00:00
parent 5176caf4d2
commit 7d27fd3796
28 changed files with 3128 additions and 3025 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
// Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
@ -25,16 +25,18 @@ namespace spot
{
namespace ltl
{
class destroy_visitor : public postfix_visitor
namespace
{
public:
virtual void
doit_default(formula* c)
class destroy_visitor: public postfix_visitor
{
formula::unref(c);
}
};
public:
virtual void
doit_default(formula* c)
{
formula::unref(c);
}
};
}
void
destroy(const formula* f)

View file

@ -29,99 +29,101 @@ namespace spot
{
namespace ltl
{
class dotty_visitor : public const_visitor
namespace
{
public:
typedef Sgi::hash_map<const formula*, int, ptr_hash<formula> > map;
dotty_visitor(std::ostream& os, map& m)
: os_(os), father_(-1), node_(m)
class dotty_visitor: public const_visitor
{
}
public:
typedef Sgi::hash_map<const formula*, int, ptr_hash<formula> > map;
dotty_visitor(std::ostream& os, map& m)
: os_(os), father_(-1), node_(m)
{
}
virtual
~dotty_visitor()
{
}
virtual
~dotty_visitor()
{
}
void
visit(const atomic_prop* ap)
{
draw_node_(ap, ap->name(), true);
}
void
visit(const atomic_prop* ap)
{
draw_node_(ap, ap->name(), true);
}
void
visit(const constant* c)
{
draw_node_(c, c->val_name(), true);
}
void
visit(const constant* c)
{
draw_node_(c, c->val_name(), true);
}
void
visit(const binop* bo)
{
if (draw_node_(bo, bo->op_name()))
{
dotty_visitor v(*this);
bo->first()->accept(v);
bo->second()->accept(*this);
}
}
void
visit(const binop* bo)
{
if (draw_node_(bo, bo->op_name()))
{
dotty_visitor v(*this);
bo->first()->accept(v);
bo->second()->accept(*this);
}
}
void
visit(const unop* uo)
{
if (draw_node_(uo, uo->op_name()))
uo->child()->accept(*this);
}
void
visit(const unop* uo)
{
if (draw_node_(uo, uo->op_name()))
uo->child()->accept(*this);
}
void
visit(const multop* mo)
{
if (!draw_node_(mo, mo->op_name()))
return;
unsigned max = mo->size();
for (unsigned n = 0; n < max; ++n)
{
dotty_visitor v(*this);
mo->nth(n)->accept(v);
}
}
private:
std::ostream& os_;
int father_;
map& node_;
void
visit(const multop* mo)
{
if (!draw_node_(mo, mo->op_name()))
return;
unsigned max = mo->size();
for (unsigned n = 0; n < max; ++n)
{
dotty_visitor v(*this);
mo->nth(n)->accept(v);
}
}
private:
std::ostream& os_;
int father_;
map& node_;
bool
draw_node_(const formula* f, const std::string& str, bool rec = false)
{
map::iterator i = node_.find(f);
int node;
bool node_exists = false;
if (i != node_.end())
{
node = i->second;
node_exists = true;
}
else
{
node = node_.size();
node_[f] = node;
}
// the link
if (father_ >= 0)
os_ << " " << father_ << " -> " << node << ";" << std::endl;
father_ = node;
// the node
if (node_exists)
return false;
os_ << " " << node
<< " [label=\"" << str << "\"";
if (rec)
os_ << ", shape=box";
os_ << "];" << std::endl;
return true;
}
};
bool
draw_node_(const formula* f, const std::string& str, bool rec = false)
{
map::iterator i = node_.find(f);
int node;
bool node_exists = false;
if (i != node_.end())
{
node = i->second;
node_exists = true;
}
else
{
node = node_.size();
node_[f] = node;
}
// the link
if (father_ >= 0)
os_ << " " << father_ << " -> " << node << ";" << std::endl;
father_ = node;
// the node
if (node_exists)
return false;
os_ << " " << node
<< " [label=\"" << str << "\"";
if (rec)
os_ << ", shape=box";
os_ << "];" << std::endl;
return true;
}
};
}
std::ostream&
dotty(std::ostream& os, const formula* f)

View file

@ -28,66 +28,68 @@ namespace spot
{
namespace ltl
{
class dump_visitor : public const_visitor
namespace
{
public:
dump_visitor(std::ostream& os)
: os_(os)
class dump_visitor: public const_visitor
{
}
public:
dump_visitor(std::ostream& os)
: os_(os)
{
}
virtual
~dump_visitor()
{
}
virtual
~dump_visitor()
{
}
void
visit(const atomic_prop* ap)
{
os_ << "AP(" << ap->name() << ")";
}
void
visit(const atomic_prop* ap)
{
os_ << "AP(" << ap->name() << ")";
}
void
visit(const constant* c)
{
os_ << "constant(" << c->val_name() << ")";
}
void
visit(const constant* c)
{
os_ << "constant(" << c->val_name() << ")";
}
void
visit(const binop* bo)
{
os_ << "binop(" << bo->op_name() << ", ";
bo->first()->accept(*this);
os_ << ", ";
bo->second()->accept(*this);
os_ << ")";
}
void
visit(const binop* bo)
{
os_ << "binop(" << bo->op_name() << ", ";
bo->first()->accept(*this);
os_ << ", ";
bo->second()->accept(*this);
os_ << ")";
}
void
visit(const unop* uo)
{
os_ << "unop(" << uo->op_name() << ", ";
uo->child()->accept(*this);
os_ << ")";
}
void
visit(const unop* uo)
{
os_ << "unop(" << uo->op_name() << ", ";
uo->child()->accept(*this);
os_ << ")";
}
void
visit(const multop* mo)
{
os_ << "multop(" << mo->op_name() << ", ";
unsigned max = mo->size();
mo->nth(0)->accept(*this);
for (unsigned n = 1; n < max; ++n)
{
os_ << ", ";
mo->nth(n)->accept(*this);
}
os_ << ")";
}
private:
std::ostream& os_;
};
void
visit(const multop* mo)
{
os_ << "multop(" << mo->op_name() << ", ";
unsigned max = mo->size();
mo->nth(0)->accept(*this);
for (unsigned n = 1; n < max; ++n)
{
os_ << ", ";
mo->nth(n)->accept(*this);
}
os_ << ")";
}
private:
std::ostream& os_;
};
}
std::ostream&
dump(std::ostream& os, const formula* f)

View file

@ -27,62 +27,64 @@ namespace spot
{
namespace ltl
{
class length_visitor : public const_visitor
namespace
{
public:
length_visitor()
class length_visitor: public const_visitor
{
result_ = 0;
}
public:
virtual
~length_visitor()
{
}
length_visitor()
{
result_ = 0;
}
int
result() const
{
return result_;
}
virtual
~length_visitor()
{
}
void
visit(const atomic_prop*)
{
result_ = 1;
}
int
result() const
{
return result_;
}
void
visit(const constant*)
{
result_ = 1;
}
void
visit(const atomic_prop*)
{
result_ = 1;
}
void
visit(const unop* uo)
{
result_ = 1 + length(uo->child());
}
void
visit(const constant*)
{
result_ = 1;
}
void
visit(const binop* bo)
{
result_ = 1 + length(bo->first()) + length(bo->second());
}
void
visit(const unop* uo)
{
result_ = 1 + length(uo->child());
}
void
visit(const multop* mo)
{
unsigned mos = mo->size();
for (unsigned i = 0; i < mos; ++i)
result_ += length(mo->nth(i));
}
void
visit(const binop* bo)
{
result_ = 1 + length(bo->first()) + length(bo->second());
}
protected:
int result_; // size of the formula
};
void
visit(const multop* mo)
{
unsigned mos = mo->size();
for (unsigned i = 0; i < mos; ++i)
result_ += length(mo->nth(i));
}
protected:
int result_; // size of the formula
};
}
int
length(const formula* f)

View file

@ -27,166 +27,170 @@ namespace spot
{
namespace ltl
{
class negative_normal_form_visitor : public visitor
namespace
{
public:
negative_normal_form_visitor(bool negated)
: negated_(negated)
class negative_normal_form_visitor: public visitor
{
}
public:
negative_normal_form_visitor(bool negated)
: negated_(negated)
{
}
virtual
~negative_normal_form_visitor()
{
}
virtual
~negative_normal_form_visitor()
{
}
formula* result() const
{
return result_;
}
formula* result() const
{
return result_;
}
void
visit(atomic_prop* ap)
{
formula* f = ap->ref();
if (negated_)
result_ = unop::instance(unop::Not, f);
else
result_ = f;
}
void
visit(atomic_prop* ap)
{
formula* f = ap->ref();
if (negated_)
result_ = unop::instance(unop::Not, f);
else
result_ = f;
}
void
visit(constant* c)
{
if (!negated_)
{
result_ = c;
return;
}
switch (c->val())
{
case constant::True:
result_ = constant::false_instance();
return;
case constant::False:
result_ = constant::true_instance();
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(unop* uo)
{
formula* f = uo->child();
switch (uo->op())
{
case unop::Not:
result_ = recurse_(f, negated_ ^ true);
return;
case unop::X:
/* !Xa == X!a */
result_ = unop::instance(unop::X, recurse(f));
return;
case unop::F:
/* !Fa == G!a */
result_ = unop::instance(negated_ ? unop::G : unop::F, recurse(f));
return;
case unop::G:
/* !Ga == F!a */
result_ = unop::instance(negated_ ? unop::F : unop::G, recurse(f));
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(binop* bo)
{
formula* f1 = bo->first();
formula* f2 = bo->second();
switch (bo->op())
{
case binop::Xor:
/* !(a ^ b) == a <=> b */
result_ = binop::instance(negated_ ? binop::Equiv : binop::Xor,
recurse_(f1, false),
recurse_(f2, false));
return;
case binop::Equiv:
/* !(a <=> b) == a ^ b */
result_ = binop::instance(negated_ ? binop::Xor : binop::Equiv,
recurse_(f1, false),
recurse_(f2, false));
return;
case binop::Implies:
if (negated_)
/* !(a => b) == a & !b */
result_ = multop::instance(multop::And,
recurse_(f1, false),
recurse_(f2, true));
else
result_ = binop::instance(binop::Implies,
recurse(f1), recurse(f2));
return;
case binop::U:
/* !(a U b) == !a R !b */
result_ = binop::instance(negated_ ? binop::R : binop::U,
recurse(f1), recurse(f2));
return;
case binop::R:
/* !(a R b) == !a U !b */
result_ = binop::instance(negated_ ? binop::U : binop::R,
recurse(f1), recurse(f2));
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(multop* mo)
{
/* !(a & b & c) == !a | !b | !c */
/* !(a | b | c) == !a & !b & !c */
multop::type op = mo->op();
if (negated_)
switch (op)
void
visit(constant* c)
{
if (!negated_)
{
case multop::And:
op = multop::Or;
break;
case multop::Or:
op = multop::And;
break;
result_ = c;
return;
}
multop::vec* res = new multop::vec;
unsigned mos = mo->size();
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
result_ = multop::instance(op, res);
}
formula*
recurse_(formula* f, bool negated)
{
return negative_normal_form(f, negated);
}
switch (c->val())
{
case constant::True:
result_ = constant::false_instance();
return;
case constant::False:
result_ = constant::true_instance();
return;
}
/* Unreachable code. */
assert(0);
}
formula*
recurse(formula* f)
{
return recurse_(f, negated_);
}
void
visit(unop* uo)
{
formula* f = uo->child();
switch (uo->op())
{
case unop::Not:
result_ = recurse_(f, negated_ ^ true);
return;
case unop::X:
/* !Xa == X!a */
result_ = unop::instance(unop::X, recurse(f));
return;
case unop::F:
/* !Fa == G!a */
result_ = unop::instance(negated_ ? unop::G : unop::F,
recurse(f));
return;
case unop::G:
/* !Ga == F!a */
result_ = unop::instance(negated_ ? unop::F : unop::G,
recurse(f));
return;
}
/* Unreachable code. */
assert(0);
}
protected:
formula* result_;
bool negated_;
};
void
visit(binop* bo)
{
formula* f1 = bo->first();
formula* f2 = bo->second();
switch (bo->op())
{
case binop::Xor:
/* !(a ^ b) == a <=> b */
result_ = binop::instance(negated_ ? binop::Equiv : binop::Xor,
recurse_(f1, false),
recurse_(f2, false));
return;
case binop::Equiv:
/* !(a <=> b) == a ^ b */
result_ = binop::instance(negated_ ? binop::Xor : binop::Equiv,
recurse_(f1, false),
recurse_(f2, false));
return;
case binop::Implies:
if (negated_)
/* !(a => b) == a & !b */
result_ = multop::instance(multop::And,
recurse_(f1, false),
recurse_(f2, true));
else
result_ = binop::instance(binop::Implies,
recurse(f1), recurse(f2));
return;
case binop::U:
/* !(a U b) == !a R !b */
result_ = binop::instance(negated_ ? binop::R : binop::U,
recurse(f1), recurse(f2));
return;
case binop::R:
/* !(a R b) == !a U !b */
result_ = binop::instance(negated_ ? binop::U : binop::R,
recurse(f1), recurse(f2));
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(multop* mo)
{
/* !(a & b & c) == !a | !b | !c */
/* !(a | b | c) == !a & !b & !c */
multop::type op = mo->op();
if (negated_)
switch (op)
{
case multop::And:
op = multop::Or;
break;
case multop::Or:
op = multop::And;
break;
}
multop::vec* res = new multop::vec;
unsigned mos = mo->size();
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
result_ = multop::instance(op, res);
}
formula*
recurse_(formula* f, bool negated)
{
return negative_normal_form(f, negated);
}
formula*
recurse(formula* f)
{
return recurse_(f, negated_);
}
protected:
formula* result_;
bool negated_;
};
}
formula*
negative_normal_form(const formula* f, bool negated)

View file

@ -34,258 +34,261 @@ namespace spot
{
namespace ltl
{
class reduce_visitor : public visitor
namespace
{
public:
reduce_visitor(int opt)
: opt_(opt)
class reduce_visitor: public visitor
{
}
public:
virtual ~reduce_visitor()
{
}
reduce_visitor(int opt)
: opt_(opt)
{
}
formula*
result() const
{
return result_;
}
virtual ~reduce_visitor()
{
}
void
visit(atomic_prop* ap)
{
formula* f = ap->ref();
result_ = f;
}
formula*
result() const
{
return result_;
}
void
visit(constant* c)
{
result_ = c;
}
void
visit(atomic_prop* ap)
{
formula* f = ap->ref();
result_ = f;
}
void
visit(unop* uo)
{
result_ = recurse(uo->child());
void
visit(constant* c)
{
result_ = c;
}
switch (uo->op())
{
case unop::Not:
result_ = unop::instance(unop::Not, result_);
return;
void
visit(unop* uo)
{
result_ = recurse(uo->child());
case unop::X:
result_ = unop::instance(unop::X, result_);
return;
switch (uo->op())
{
case unop::Not:
result_ = unop::instance(unop::Not, result_);
return;
case unop::F:
/* If f is a pure eventuality formula then F(f)=f. */
if (!(opt_ & Reduce_Eventuality_And_Universality)
|| !is_eventual(result_))
result_ = unop::instance(unop::F, result_);
return;
case unop::X:
result_ = unop::instance(unop::X, result_);
return;
case unop::G:
/* If f is a pure universality formula then G(f)=f. */
if (!(opt_ & Reduce_Eventuality_And_Universality)
|| !is_universal(result_))
result_ = unop::instance(unop::G, result_);
return;
}
/* Unreachable code. */
assert(0);
}
case unop::F:
/* If f is a pure eventuality formula then F(f)=f. */
if (!(opt_ & Reduce_Eventuality_And_Universality)
|| !is_eventual(result_))
result_ = unop::instance(unop::F, result_);
return;
void
visit(binop* bo)
{
formula* f2 = recurse(bo->second());
case unop::G:
/* If f is a pure universality formula then G(f)=f. */
if (!(opt_ & Reduce_Eventuality_And_Universality)
|| !is_universal(result_))
result_ = unop::instance(unop::G, result_);
return;
}
/* Unreachable code. */
assert(0);
}
/* If b is a pure eventuality formula then a U b = b.
If b is a pure universality formula a R b = b. */
if ((opt_ & Reduce_Eventuality_And_Universality)
&& ((is_eventual(f2) && ((bo->op()) == binop::U))
|| (is_universal(f2) && ((bo->op()) == binop::R))))
{
result_ = f2;
return;
}
/* case of implies */
formula* f1 = recurse(bo->first());
void
visit(binop* bo)
{
formula* f2 = recurse(bo->second());
if (opt_ & Reduce_Syntactic_Implications)
{
// FIXME: These should be done only when needed.
bool inf = syntactic_implication(f1, f2);
bool infinv = syntactic_implication(f2, f1);
bool infnegleft = syntactic_implication_neg(f2, f1, false);
bool infnegright = syntactic_implication_neg(f2, f1, true);
/* If b is a pure eventuality formula then a U b = b.
If b is a pure universality formula a R b = b. */
if ((opt_ & Reduce_Eventuality_And_Universality)
&& ((is_eventual(f2) && ((bo->op()) == binop::U))
|| (is_universal(f2) && ((bo->op()) == binop::R))))
{
result_ = f2;
return;
}
/* case of implies */
formula* f1 = recurse(bo->first());
switch (bo->op())
{
case binop::Xor:
case binop::Equiv:
case binop::Implies:
break;
if (opt_ & Reduce_Syntactic_Implications)
{
// FIXME: These should be done only when needed.
bool inf = syntactic_implication(f1, f2);
bool infinv = syntactic_implication(f2, f1);
bool infnegleft = syntactic_implication_neg(f2, f1, false);
bool infnegright = syntactic_implication_neg(f2, f1, true);
case binop::U:
/* a < b => a U b = b */
if (inf)
{
result_ = f2;
destroy(f1);
return;
}
/* !b < a => a U b = Fb */
if (infnegleft)
{
result_ = unop::instance(unop::F, f2);
destroy(f1);
return;
}
/* a < b => a U (b U c) = (b U c) */
switch (bo->op())
{
binop* bo = dynamic_cast<binop*>(f2);
if (bo && bo->op() == binop::U
&& syntactic_implication(f1, bo->first()))
case binop::Xor:
case binop::Equiv:
case binop::Implies:
break;
case binop::U:
/* a < b => a U b = b */
if (inf)
{
result_ = f2;
destroy(f1);
return;
}
}
break;
/* !b < a => a U b = Fb */
if (infnegleft)
{
result_ = unop::instance(unop::F, f2);
destroy(f1);
return;
}
/* a < b => a U (b U c) = (b U c) */
{
binop* bo = dynamic_cast<binop*>(f2);
if (bo && bo->op() == binop::U
&& syntactic_implication(f1, bo->first()))
{
result_ = f2;
destroy(f1);
return;
}
}
break;
case binop::R:
/* b < a => a R b = b */
if (infinv)
{
result_ = f2;
destroy(f1);
return;
}
/* b < !a => a R b = Gb */
if (infnegright)
{
result_ = unop::instance(unop::G, f2);
destroy(f1);
return;
}
/* b < a => a R (b R c) = b R c */
{
binop* bo = dynamic_cast<binop*>(f2);
if (bo && bo->op() == binop::R
&& syntactic_implication(bo->first(), f1))
case binop::R:
/* b < a => a R b = b */
if (infinv)
{
result_ = f2;
destroy(f1);
return;
}
/* b < !a => a R b = Gb */
if (infnegright)
{
result_ = unop::instance(unop::G, f2);
destroy(f1);
return;
}
/* b < a => a R (b R c) = b R c */
{
binop* bo = dynamic_cast<binop*>(f2);
if (bo && bo->op() == binop::R
&& syntactic_implication(bo->first(), f1))
{
result_ = f2;
destroy(f1);
return;
}
}
break;
}
break;
}
}
result_ = binop::instance(bo->op(), f1, f2);
}
}
result_ = binop::instance(bo->op(), f1, f2);
}
void
visit(multop* mo)
{
unsigned mos = mo->size();
multop::vec* res = new multop::vec;
void
visit(multop* mo)
{
unsigned mos = mo->size();
multop::vec* res = new multop::vec;
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
for (unsigned i = 0; i < mos; ++i)
res->push_back(recurse(mo->nth(i)));
if (opt_ & Reduce_Syntactic_Implications)
{
if (opt_ & Reduce_Syntactic_Implications)
{
bool removed = true;
multop::vec::iterator f1;
multop::vec::iterator f2;
bool removed = true;
multop::vec::iterator f1;
multop::vec::iterator f2;
while (removed)
{
removed = false;
f2 = f1 = res->begin();
++f1;
while (f1 != res->end())
{
assert(f1 != f2);
// a < b => a + b = b
// a < b => a & b = a
if ((syntactic_implication(*f1, *f2) && // f1 < f2
(mo->op() == multop::Or)) ||
((syntactic_implication(*f2, *f1)) && // f2 < f1
(mo->op() == multop::And)))
{
// We keep f2
destroy(*f1);
res->erase(f1);
removed = true;
break;
}
else if ((syntactic_implication(*f2, *f1) && // f2 < f1
(mo->op() == multop::Or)) ||
((syntactic_implication(*f1, *f2)) && // f1 < f2
(mo->op() == multop::And)))
{
// We keep f1
destroy(*f2);
res->erase(f2);
removed = true;
break;
}
else
++f1;
}
}
while (removed)
{
removed = false;
f2 = f1 = res->begin();
++f1;
while (f1 != res->end())
{
assert(f1 != f2);
// a < b => a + b = b
// a < b => a & b = a
if ((syntactic_implication(*f1, *f2) && // f1 < f2
(mo->op() == multop::Or)) ||
((syntactic_implication(*f2, *f1)) && // f2 < f1
(mo->op() == multop::And)))
{
// We keep f2
destroy(*f1);
res->erase(f1);
removed = true;
break;
}
else if ((syntactic_implication(*f2, *f1) && // f2 < f1
(mo->op() == multop::Or)) ||
((syntactic_implication(*f1, *f2)) && // f1 < f2
(mo->op() == multop::And)))
{
// We keep f1
destroy(*f2);
res->erase(f2);
removed = true;
break;
}
else
++f1;
}
}
// FIXME
/* f1 < !f2 => f1 & f2 = false
!f1 < f2 => f1 | f2 = true */
for (f1 = res->begin(); f1 != res->end(); f1++)
for (f2 = res->begin(); f2 != res->end(); f2++)
if (f1 != f2 &&
syntactic_implication_neg(*f1, *f2,
mo->op() != multop::Or))
{
for (multop::vec::iterator j = res->begin();
j != res->end(); j++)
destroy(*j);
res->clear();
delete res;
if (mo->op() == multop::Or)
result_ = constant::true_instance();
else
result_ = constant::false_instance();
return;
}
// FIXME
/* f1 < !f2 => f1 & f2 = false
!f1 < f2 => f1 | f2 = true */
for (f1 = res->begin(); f1 != res->end(); f1++)
for (f2 = res->begin(); f2 != res->end(); f2++)
if (f1 != f2 &&
syntactic_implication_neg(*f1, *f2,
mo->op() != multop::Or))
{
for (multop::vec::iterator j = res->begin();
j != res->end(); j++)
destroy(*j);
res->clear();
delete res;
if (mo->op() == multop::Or)
result_ = constant::true_instance();
else
result_ = constant::false_instance();
return;
}
}
}
if (!res->empty())
{
result_ = multop::instance(mo->op(), res);
return;
}
assert(0);
}
if (!res->empty())
{
result_ = multop::instance(mo->op(), res);
return;
}
assert(0);
}
formula*
recurse(formula* f)
{
return reduce(f, opt_);
}
formula*
recurse(formula* f)
{
return reduce(f, opt_);
}
protected:
formula* result_;
int opt_;
};
protected:
formula* result_;
int opt_;
};
} // anonymous
formula*
reduce(const formula* f, int opt)

View file

@ -32,135 +32,489 @@ namespace spot
{
namespace ltl
{
class eventual_universal_visitor : public const_visitor
namespace
{
public:
eventual_universal_visitor()
: eventual(false), universal(false)
class eventual_universal_visitor: public const_visitor
{
}
public:
virtual
~eventual_universal_visitor()
{
}
eventual_universal_visitor()
: eventual(false), universal(false)
{
}
bool
is_eventual() const
{
return eventual;
}
virtual
~eventual_universal_visitor()
{
}
bool
is_universal() const
{
return universal;
}
bool
is_eventual() const
{
return eventual;
}
void
visit(const atomic_prop*)
{
}
bool
is_universal() const
{
return universal;
}
void
visit(const constant*)
{
}
void
visit(const atomic_prop*)
{
}
void
visit(const unop* uo)
{
const formula* f1 = uo->child();
if (uo->op() == unop::F)
{
eventual = true;
universal = recurse_un(f1);
return;
}
if (uo->op() == unop::G)
{
universal = true;
eventual = recurse_ev(f1);
}
}
void
visit(const constant*)
{
}
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:
universal = recurse_un(f1) & recurse_un(f2);
if ((f1 == constant::true_instance()) ||
(recurse_ev(f1)))
void
visit(const unop* uo)
{
const formula* f1 = uo->child();
if (uo->op() == unop::F)
{
eventual = true;
return;
case binop::R:
eventual = recurse_ev(f1) & recurse_ev(f2);
if ((f1 == constant::false_instance()))
//||
//(recurse_un(f1)))
universal = recurse_un(f1);
return;
}
if (uo->op() == unop::G)
{
universal = true;
if (!universal)
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);
return;
}
/* Unreachable code. */
assert(0);
}
eventual = recurse_ev(f1) & recurse_ev(f2);
return;
case binop::U:
universal = recurse_un(f1) & recurse_un(f2);
if ((f1 == constant::true_instance()) ||
(recurse_ev(f1)))
eventual = true;
return;
case binop::R:
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. */
assert(0);
}
void
visit(const multop* mo)
void
visit(const multop* mo)
{
unsigned mos = mo->size();
eventual = true;
universal = true;
for (unsigned i = 0; i < mos; ++i)
if (!recurse_ev(mo->nth(i)))
{
eventual = false;
break;
}
for (unsigned i = 0; i < mos; ++i)
if (!recurse_un(mo->nth(i)))
{
universal = false;
break;
}
}
bool
recurse_ev(const formula* f)
{
eventual_universal_visitor v;
const_cast<formula*>(f)->accept(v);
return v.is_eventual();
}
bool
recurse_un(const formula* f)
{
eventual_universal_visitor v;
const_cast<formula*>(f)->accept(v);
return v.is_universal();
}
protected:
bool eventual;
bool universal;
};
/////////////////////////////////////////////////////////////////////////
class inf_right_recurse_visitor: public const_visitor
{
unsigned mos = mo->size();
public:
eventual = true;
universal = true;
for (unsigned i = 0; i < mos; ++i)
if (!recurse_ev(mo->nth(i)))
inf_right_recurse_visitor(const formula *f)
: result_(false), f(f)
{
}
virtual
~inf_right_recurse_visitor()
{
}
int
result() const
{
return result_;
}
void
visit(const atomic_prop* ap)
{
if (dynamic_cast<const atomic_prop*>(f) == ap)
result_ = true;
}
void
visit(const constant* c)
{
switch (c->val())
{
eventual = false;
case constant::True:
result_ = true;
return;
case constant::False:
result_ = false;
return;
}
}
void
visit(const unop* uo)
{
const formula* f1 = uo->child();
switch (uo->op())
{
case unop::Not:
if (uo == f)
result_ = true;
return;
case unop::X:
{
const unop* op = dynamic_cast<const unop*>(f);
if (op && op->op() == unop::X)
result_ = syntactic_implication(op->child(), f1);
}
return;
case unop::F:
/* F(a) = true U a */
result_ = syntactic_implication(f, f1);
return;
case unop::G:
/* G(a) = false R a */
if (syntactic_implication(f, constant::false_instance()))
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const binop* bo)
{
const formula* f1 = bo->first();
const formula* f2 = bo->second();
const binop* fb = dynamic_cast<const binop*>(f);
const unop* fu = dynamic_cast<const unop*>(f);
switch (bo->op())
{
case binop::Xor:
case binop::Equiv:
case binop::Implies:
return;
case binop::U:
if (syntactic_implication(f, f2))
result_ = true;
return;
case binop::R:
if (fb && fb->op() == binop::R)
if (syntactic_implication(fb->first(), f1) &&
syntactic_implication(fb->second(), f2))
{
result_ = true;
return;
}
if (fu && fu->op() == unop::G)
if (f1 == constant::false_instance() &&
syntactic_implication(fu->child(), f2))
{
result_ = true;
return;
}
if (syntactic_implication(f, f1)
&& syntactic_implication(f, f2))
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const multop* mo)
{
multop::type op = mo->op();
unsigned mos = mo->size();
switch (op)
{
case multop::And:
for (unsigned i = 0; i < mos; ++i)
if (!syntactic_implication(f, mo->nth(i)))
return;
result_ = true;
break;
case multop::Or:
for (unsigned i = 0; i < mos && !result_; ++i)
if (syntactic_implication(f, mo->nth(i)))
result_ = true;
break;
}
for (unsigned i = 0; i < mos; ++i)
if (!recurse_un(mo->nth(i)))
}
bool
recurse(const formula* f1, const formula* f2)
{
if (f1 == f2)
return true;
inf_right_recurse_visitor v(f2);
const_cast<formula*>(f1)->accept(v);
return v.result();
}
protected:
bool result_; /* true if f < f1, false otherwise. */
const formula* f;
};
/////////////////////////////////////////////////////////////////////////
class inf_left_recurse_visitor: public const_visitor
{
public:
inf_left_recurse_visitor(const formula *f)
: result_(false), f(f)
{
}
virtual
~inf_left_recurse_visitor()
{
}
bool
special_case(const formula* f2)
{
const binop* fb = dynamic_cast<const binop*>(f);
const binop* f2b = dynamic_cast<const binop*>(f2);
if (fb && f2b && fb->op() == f2b->op()
&& syntactic_implication(f2b->first(), fb->first())
&& syntactic_implication(f2b->second(), fb->second()))
return true;
return false;
}
int
result() const
{
return result_;
}
void
visit(const atomic_prop* ap)
{
inf_right_recurse_visitor v(ap);
const_cast<formula*>(f)->accept(v);
result_ = v.result();
}
void
visit(const constant* c)
{
inf_right_recurse_visitor v(c);
switch (c->val())
{
universal = false;
case constant::True:
const_cast<formula*>(f)->accept(v);
result_ = v.result();
return;
case constant::False:
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const unop* uo)
{
const formula* f1 = uo->child();
inf_right_recurse_visitor v(uo);
switch (uo->op())
{
case unop::Not:
if (uo == f)
result_ = true;
return;
case unop::X:
{
const unop* op = dynamic_cast<const unop*>(f);
if (op && op->op() == unop::X)
result_ = syntactic_implication(f1, op->child());
}
return;
case unop::F:
{
/* F(a) = true U a */
const formula* tmp = binop::instance(binop::U,
constant::true_instance(),
clone(f1));
if (special_case(tmp))
{
result_ = true;
destroy(tmp);
return;
}
if (syntactic_implication(tmp, f))
result_ = true;
destroy(tmp);
return;
}
case unop::G:
{
/* G(a) = false R a */
const formula* tmp = binop::instance(binop::R,
constant::false_instance(),
clone(f1));
if (special_case(tmp))
{
result_ = true;
destroy(tmp);
return;
}
if (syntactic_implication(tmp, f))
result_ = true;
destroy(tmp);
return;
}
}
/* Unreachable code. */
assert(0);
}
void
visit(const binop* bo)
{
if (special_case(bo))
{
result_ = true;
return;
}
const formula* f1 = bo->first();
const formula* f2 = bo->second();
const binop* fb = dynamic_cast<const binop*>(f);
const unop* fu = dynamic_cast<const unop*>(f);
switch (bo->op())
{
case binop::Xor:
case binop::Equiv:
case binop::Implies:
return;
case binop::U:
/* (a < c) && (c < d) => a U b < c U d */
if (fb && fb->op() == binop::U)
if (syntactic_implication(f1, fb->first()) &&
syntactic_implication(f2, fb->second()))
{
result_ = true;
return;
}
if (fu && fu->op() == unop::F)
if (f1 == constant::true_instance() &&
syntactic_implication(f2, fu->child()))
{
result_ = true;
return;
}
if (syntactic_implication(f1, f)
&& syntactic_implication(f2, f))
result_ = true;
return;
case binop::R:
if (fu && fu->op() == unop::G)
if (f1 == constant::false_instance() &&
syntactic_implication(f2, fu->child()))
{
result_ = true;
return;
}
if (syntactic_implication(f2, f))
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const multop* mo)
{
multop::type op = mo->op();
unsigned mos = mo->size();
switch (op)
{
case multop::And:
for (unsigned i = 0; (i < mos) && !result_; ++i)
if (syntactic_implication(mo->nth(i), f))
result_ = true;
break;
case multop::Or:
for (unsigned i = 0; i < mos; ++i)
if (!syntactic_implication(mo->nth(i), f))
return;
result_ = true;
break;
}
}
}
bool
recurse_ev(const formula* f)
{
eventual_universal_visitor v;
const_cast<formula*>(f)->accept(v);
return v.is_eventual();
}
bool
recurse_un(const formula* f)
{
eventual_universal_visitor v;
const_cast<formula*>(f)->accept(v);
return v.is_universal();
}
protected:
bool eventual;
bool universal;
};
protected:
bool result_; /* true if f1 < f, 1 otherwise. */
const formula* f;
};
} // anonymous
bool
is_eventual(const formula* f)
@ -178,356 +532,6 @@ namespace spot
return v.is_universal();
}
/////////////////////////////////////////////////////////////////////////
class inf_right_recurse_visitor : public const_visitor
{
public:
inf_right_recurse_visitor(const formula *f)
: result_(false), f(f)
{
}
virtual
~inf_right_recurse_visitor()
{
}
int
result() const
{
return result_;
}
void
visit(const atomic_prop* ap)
{
if (dynamic_cast<const atomic_prop*>(f) == ap)
result_ = true;
}
void
visit(const constant* c)
{
switch (c->val())
{
case constant::True:
result_ = true;
return;
case constant::False:
result_ = false;
return;
}
}
void
visit(const unop* uo)
{
const formula* f1 = uo->child();
switch (uo->op())
{
case unop::Not:
if (uo == f)
result_ = true;
return;
case unop::X:
{
const unop* op = dynamic_cast<const unop*>(f);
if (op && op->op() == unop::X)
result_ = syntactic_implication(op->child(), f1);
}
return;
case unop::F:
/* F(a) = true U a */
result_ = syntactic_implication(f, f1);
return;
case unop::G:
/* G(a) = false R a */
if (syntactic_implication(f, constant::false_instance()))
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const binop* bo)
{
const formula* f1 = bo->first();
const formula* f2 = bo->second();
const binop* fb = dynamic_cast<const binop*>(f);
const unop* fu = dynamic_cast<const unop*>(f);
switch (bo->op())
{
case binop::Xor:
case binop::Equiv:
case binop::Implies:
return;
case binop::U:
if (syntactic_implication(f, f2))
result_ = true;
return;
case binop::R:
if (fb && fb->op() == binop::R)
if (syntactic_implication(fb->first(), f1) &&
syntactic_implication(fb->second(), f2))
{
result_ = true;
return;
}
if (fu && fu->op() == unop::G)
if (f1 == constant::false_instance() &&
syntactic_implication(fu->child(), f2))
{
result_ = true;
return;
}
if (syntactic_implication(f, f1)
&& syntactic_implication(f, f2))
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const multop* mo)
{
multop::type op = mo->op();
unsigned mos = mo->size();
switch (op)
{
case multop::And:
for (unsigned i = 0; i < mos; ++i)
if (!syntactic_implication(f, mo->nth(i)))
return;
result_ = true;
break;
case multop::Or:
for (unsigned i = 0; i < mos && !result_; ++i)
if (syntactic_implication(f, mo->nth(i)))
result_ = true;
break;
}
}
bool
recurse(const formula* f1, const formula* f2)
{
if (f1 == f2)
return true;
inf_right_recurse_visitor v(f2);
const_cast<formula*>(f1)->accept(v);
return v.result();
}
protected:
bool result_; /* true if f < f1, false otherwise. */
const formula* f;
};
/////////////////////////////////////////////////////////////////////////
class inf_left_recurse_visitor : public const_visitor
{
public:
inf_left_recurse_visitor(const formula *f)
: result_(false), f(f)
{
}
virtual
~inf_left_recurse_visitor()
{
}
bool
special_case(const formula* f2)
{
const binop* fb = dynamic_cast<const binop*>(f);
const binop* f2b = dynamic_cast<const binop*>(f2);
if (fb && f2b && fb->op() == f2b->op()
&& syntactic_implication(f2b->first(), fb->first())
&& syntactic_implication(f2b->second(), fb->second()))
return true;
return false;
}
int
result() const
{
return result_;
}
void
visit(const atomic_prop* ap)
{
inf_right_recurse_visitor v(ap);
const_cast<formula*>(f)->accept(v);
result_ = v.result();
}
void
visit(const constant* c)
{
inf_right_recurse_visitor v(c);
switch (c->val())
{
case constant::True:
const_cast<formula*>(f)->accept(v);
result_ = v.result();
return;
case constant::False:
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const unop* uo)
{
const formula* f1 = uo->child();
inf_right_recurse_visitor v(uo);
switch (uo->op())
{
case unop::Not:
if (uo == f)
result_ = true;
return;
case unop::X:
{
const unop* op = dynamic_cast<const unop*>(f);
if (op && op->op() == unop::X)
result_ = syntactic_implication(f1, op->child());
}
return;
case unop::F:
{
/* F(a) = true U a */
const formula* tmp = binop::instance(binop::U,
constant::true_instance(),
clone(f1));
if (special_case(tmp))
{
result_ = true;
destroy(tmp);
return;
}
if (syntactic_implication(tmp, f))
result_ = true;
destroy(tmp);
return;
}
case unop::G:
{
/* G(a) = false R a */
const formula* tmp = binop::instance(binop::R,
constant::false_instance(),
clone(f1));
if (special_case(tmp))
{
result_ = true;
destroy(tmp);
return;
}
if (syntactic_implication(tmp, f))
result_ = true;
destroy(tmp);
return;
}
}
/* Unreachable code. */
assert(0);
}
void
visit(const binop* bo)
{
if (special_case(bo))
{
result_ = true;
return;
}
const formula* f1 = bo->first();
const formula* f2 = bo->second();
const binop* fb = dynamic_cast<const binop*>(f);
const unop* fu = dynamic_cast<const unop*>(f);
switch (bo->op())
{
case binop::Xor:
case binop::Equiv:
case binop::Implies:
return;
case binop::U:
/* (a < c) && (c < d) => a U b < c U d */
if (fb && fb->op() == binop::U)
if (syntactic_implication(f1, fb->first()) &&
syntactic_implication(f2, fb->second()))
{
result_ = true;
return;
}
if (fu && fu->op() == unop::F)
if (f1 == constant::true_instance() &&
syntactic_implication(f2, fu->child()))
{
result_ = true;
return;
}
if (syntactic_implication(f1, f)
&& syntactic_implication(f2, f))
result_ = true;
return;
case binop::R:
if (fu && fu->op() == unop::G)
if (f1 == constant::false_instance() &&
syntactic_implication(f2, fu->child()))
{
result_ = true;
return;
}
if (syntactic_implication(f2, f))
result_ = true;
return;
}
/* Unreachable code. */
assert(0);
}
void
visit(const multop* mo)
{
multop::type op = mo->op();
unsigned mos = mo->size();
switch (op)
{
case multop::And:
for (unsigned i = 0; (i < mos) && !result_; ++i)
if (syntactic_implication(mo->nth(i), f))
result_ = true;
break;
case multop::Or:
for (unsigned i = 0; i < mos; ++i)
if (!syntactic_implication(mo->nth(i), f))
return;
result_ = true;
break;
}
}
protected:
bool result_; /* true if f1 < f, 1 otherwise. */
const formula* f;
};
// This is called by syntactic_implication() after the
// formulae have been normalized.
bool

View file

@ -32,159 +32,161 @@ namespace spot
{
namespace ltl
{
static bool
is_bare_word(const char* str)
namespace
{
// Bare words cannot be empty, start with the letter of a unary
// operator, or be the name of an existing constant. Also they
// should start with an letter.
if (!*str
|| *str == 'F'
|| *str == 'G'
|| *str == 'X'
|| !(isalpha(*str) || *str == '_')
|| !strcasecmp(str, "true")
|| !strcasecmp(str, "false"))
return false;
// The remaining of the word must be alphanumeric.
while (*++str)
if (!(isalnum(*str) || *str == '_'))
static bool
is_bare_word(const char* str)
{
// Bare words cannot be empty, start with the letter of a unary
// operator, or be the name of an existing constant. Also they
// should start with an letter.
if (!*str
|| *str == 'F'
|| *str == 'G'
|| *str == 'X'
|| !(isalpha(*str) || *str == '_')
|| !strcasecmp(str, "true")
|| !strcasecmp(str, "false"))
return false;
return true;
// The remaining of the word must be alphanumeric.
while (*++str)
if (!(isalnum(*str) || *str == '_'))
return false;
return true;
}
class to_string_visitor: public const_visitor
{
public:
to_string_visitor(std::ostream& os)
: os_(os), top_level_(true)
{
}
virtual
~to_string_visitor()
{
}
void
visit(const atomic_prop* ap)
{
std::string str = ap->name();
if (!is_bare_word(str.c_str()))
{
os_ << '"' << str << '"';
}
else
{
os_ << str;
}
}
void
visit(const constant* c)
{
os_ << c->val_name();
}
void
visit(const binop* bo)
{
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
bo->first()->accept(*this);
switch (bo->op())
{
case binop::Xor:
os_ << " ^ ";
break;
case binop::Implies:
os_ << " => ";
break;
case binop::Equiv:
os_ << " <=> ";
break;
case binop::U:
os_ << " U ";
break;
case binop::R:
os_ << " R ";
break;
}
bo->second()->accept(*this);
if (!top_level)
os_ << ")";
}
void
visit(const unop* uo)
{
// The parser treats F0, F1, G0, G1, X0, and X1 as atomic
// propositions. So make sure we output F(0), G(1), etc.
bool need_parent = !!dynamic_cast<const constant*>(uo->child());
switch (uo->op())
{
case unop::Not:
os_ << "!";
need_parent = false;
break;
case unop::X:
os_ << "X";
break;
case unop::F:
os_ << "F";
break;
case unop::G:
os_ << "G";
break;
}
top_level_ = false;
if (need_parent)
os_ << "(";
uo->child()->accept(*this);
if (need_parent)
os_ << ")";
}
void
visit(const multop* mo)
{
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
unsigned max = mo->size();
mo->nth(0)->accept(*this);
const char* ch = " ";
switch (mo->op())
{
case multop::Or:
ch = " | ";
break;
case multop::And:
ch = " & ";
break;
}
for (unsigned n = 1; n < max; ++n)
{
os_ << ch;
mo->nth(n)->accept(*this);
}
if (!top_level)
os_ << ")";
}
protected:
std::ostream& os_;
bool top_level_;
};
}
class to_string_visitor : public const_visitor
{
public:
to_string_visitor(std::ostream& os)
: os_(os), top_level_(true)
{
}
virtual
~to_string_visitor()
{
}
void
visit(const atomic_prop* ap)
{
std::string str = ap->name();
if (!is_bare_word(str.c_str()))
{
os_ << '"' << str << '"';
}
else
{
os_ << str;
}
}
void
visit(const constant* c)
{
os_ << c->val_name();
}
void
visit(const binop* bo)
{
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
bo->first()->accept(*this);
switch (bo->op())
{
case binop::Xor:
os_ << " ^ ";
break;
case binop::Implies:
os_ << " => ";
break;
case binop::Equiv:
os_ << " <=> ";
break;
case binop::U:
os_ << " U ";
break;
case binop::R:
os_ << " R ";
break;
}
bo->second()->accept(*this);
if (!top_level)
os_ << ")";
}
void
visit(const unop* uo)
{
// The parser treats F0, F1, G0, G1, X0, and X1 as atomic
// propositions. So make sure we output F(0), G(1), etc.
bool need_parent = !!dynamic_cast<const constant*>(uo->child());
switch (uo->op())
{
case unop::Not:
os_ << "!";
need_parent = false;
break;
case unop::X:
os_ << "X";
break;
case unop::F:
os_ << "F";
break;
case unop::G:
os_ << "G";
break;
}
top_level_ = false;
if (need_parent)
os_ << "(";
uo->child()->accept(*this);
if (need_parent)
os_ << ")";
}
void
visit(const multop* mo)
{
bool top_level = top_level_;
top_level_ = false;
if (!top_level)
os_ << "(";
unsigned max = mo->size();
mo->nth(0)->accept(*this);
const char* ch = " ";
switch (mo->op())
{
case multop::Or:
ch = " | ";
break;
case multop::And:
ch = " & ";
break;
}
for (unsigned n = 1; n < max; ++n)
{
os_ << ch;
mo->nth(n)->accept(*this);
}
if (!top_level)
os_ << ")";
}
protected:
std::ostream& os_;
bool top_level_;
};
std::ostream&
to_string(const formula* f, std::ostream& os)
{