Introduce AndRat and OrRat operator.

It was a mistake to try to overload And/Or LTL operator for these when
trivial simplification are performed.  The reason is so simple it is
embarassing: And(f,1)=f is a trivial identity that should not be
applied with AndRat.  E.g. AndRat(a;b, 1) is equal to 0, not a;b.

* src/ltlast/multop.hh, src/ltlast/multop.cc: Add the AndRat and OrRat
operators.
* src/ltlparse/ltlparse.yy: Build them.
* src/ltlvisit/mark.cc, src/ltlvisit/simplify.cc,
src/ltlvisit/tostring.cc, src/tgba/formula2bdd.cc,
src/tgbaalgos/eltl2tgba_lacim.cc, src/tgbaalgos/ltl2taa.cc,
src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/ltl2tgba_lacim.cc:
Adjust all switches.
This commit is contained in:
Alexandre Duret-Lutz 2012-04-18 19:20:43 +02:00
parent 35b41331f7
commit 691119c188
11 changed files with 916 additions and 759 deletions

View file

@ -47,11 +47,13 @@ namespace spot
is.accepting_eword = false;
case Concat:
case AndNLM:
// Note: AndNLM(p1,p2) is a Boolean formula, but it is
// actually rewritten as And(p1,p2) by trivial identities
// before this constructor is called. So at this point,
// AndNLM is always used with at most one Boolean argument,
// and the result is therefore NOT Boolean.
case AndRat:
// Note: AndNLM(p1,p2) and AndRat(p1,p2) are Boolean
// formulae, but there are actually rewritten as And(p1,p2)
// by trivial identities before this constructor is called.
// So at this point, AndNLM/AndRat are always used with at
// most one Boolean argument, and the result is therefore
// NOT Boolean.
is.boolean = false;
is.ltl_formula = false;
is.eltl_formula = false;
@ -62,6 +64,18 @@ namespace spot
for (unsigned i = 1; i < s; ++i)
props &= (*v)[i]->get_props();
break;
case OrRat:
// Note: OrRat(p1,p2) is a Boolean formula, but its is
// actually rewritten as Or(p1,p2) by trivial identities
// before this constructor is called. So at this point,
// AndNLM is always used with at most one Boolean argument,
// and the result is therefore NOT Boolean.
is.boolean = false;
is.ltl_formula = false;
is.eltl_formula = false;
is.psl_formula = false;
is.eventual = false;
is.universal = false;
case Or:
{
bool ew = (*v)[0]->accepts_eword();
@ -159,10 +173,14 @@ namespace spot
{
case And:
return "And";
case AndRat:
return "AndRat";
case AndNLM:
return "AndNLM";
case Or:
return "Or";
case OrRat:
return "OrRat";
case Concat:
return "Concat";
case Fusion:
@ -173,6 +191,37 @@ namespace spot
return 0;
}
void
gather_bool(multop::vec* v, multop::type op)
{
// Gather all boolean terms.
multop::vec* b = new multop::vec;
multop::vec::iterator i = v->begin();
while (i != v->end())
{
if ((*i)->is_boolean())
{
b->push_back(*i);
i = v->erase(i);
}
else
{
++i;
}
}
// - AndNLM(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
// AndNLM(Exps1...,Exps2...,Exps3...,And(Bool1,Bool2))
// - AndRat(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
// AndRat(Exps1...,Exps2...,Exps3...,And(Bool1,Bool2))
// - OrRat(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
// AndRat(Exps1...,Exps2...,Exps3...,Or(Bool1,Bool2))
if (!b->empty())
v->push_back(multop::instance(op, b));
else
delete b;
}
multop::map multop::instances;
// We match equivalent formulae modulo "ACI rules"
@ -246,7 +295,15 @@ namespace spot
neutral2 = 0;
abs = constant::false_instance();
abs2 = 0;
weak_abs = 0;
break;
case AndRat:
neutral = 0; /* FIXME: we should use 1[*] as neutral */
neutral2 = 0;
abs = constant::false_instance();
abs2 = 0;
weak_abs = constant::empty_word_instance();
gather_bool(v, And);
break;
case AndNLM:
neutral = constant::true_instance();
@ -254,30 +311,7 @@ namespace spot
abs = constant::false_instance();
abs2 = 0;
weak_abs = 0;
// Make a first pass to gather all boolean terms.
{
vec* b = new vec;
vec::iterator i = v->begin();
while (i != v->end())
{
if ((*i)->is_boolean())
{
b->push_back(*i);
i = v->erase(i);
}
else
{
++i;
}
}
// - AndNLM(Exps1...,Bool1,Exps2...,Bool2,Exps3...) =
// AndNLM(Exps1...,Exps2...,Exps3...,And(Bool1,Bool2))
if (!b->empty())
v->push_back(instance(And, b));
else
delete b;
}
gather_bool(v, And);
break;
case Or:
neutral = constant::false_instance();
@ -286,6 +320,14 @@ namespace spot
abs2 = 0;
weak_abs = 0;
break;
case OrRat:
neutral = constant::false_instance();
neutral2 = 0;
abs = 0; // FIXME: should be 1[*].
abs2 = 0;
weak_abs = 0;
gather_bool(v, Or);
break;
case Concat:
neutral = constant::empty_word_instance();
neutral2 = 0;
@ -377,8 +419,8 @@ namespace spot
}
}
// We have a* & [*0] & c = 0
// and a* & [*0] & c* = [*0]
// We have a* && [*0] && c = 0
// and a* && [*0] && c* = [*0]
// So if [*0] has been seen, check if alls term recognize the
// empty word.
if (weak_abs_seen)

View file

@ -41,7 +41,7 @@ namespace spot
class multop : public ref_formula
{
public:
enum type { Or, And, AndNLM, Concat, Fusion };
enum type { Or, OrRat, And, AndRat, AndNLM, Concat, Fusion };
/// List of formulae.
typedef std::vector<formula*> vec;
@ -68,24 +68,27 @@ namespace spot
/// has been passed to spot::ltl::multop. Inside the vector,
/// null pointers are ignored.
///
/// All operators (Or, And, Concat) are associative, and are
/// automatically inlined. Or and And are commutative, so their
/// argument are also sorted, to ensure that "a & b" is equal to
/// "b & a". For Or and And, duplicate arguments are also
/// removed.
/// Most operators (Or, OrRat, And, AndRat, Concat) are
/// associative, and are automatically inlined. Or, OrRat, And,
/// and AndRat are commutative, so their arguments are also
/// sorted, to ensure that "a & b" is equal to "b & a", also
/// duplicate arguments are removed.
///
/// Furthermore this function can perform slight optimizations
/// and may not return an ltl::multop object. For instance if
/// the vector contains only one unique element, this this
/// formula will be returned as-is. Neutral and absorbent element
/// are also taken care of. The following rewriting are performed
/// are also taken care of. The following rewritings are performed
/// (the left patterns are rewritten as shown on the right):
///
/// - And(Exps1...,1,Exps2...) = And(Exps1...,Exps2...)
/// - And(Exps1...,0,Exps2...) = 0
/// - And(Exps1...,[*0],Exps2...) = [*0] if all Expi accept [*0]
/// - And(Exps1...,[*0],Exps2...) = 0 if some Expi reject [*0]
/// - And(Exp) = Exp
/// - AndRat(Exps1...,0,Exps2...) = 0
/// - AndRat(Exps1...,BoolExp1,Exps2...,BoolExps2...) =
/// AndRat(Exps1...,Exps2...,And(BoolExp1,BoolExps2...))
/// - AndRat(Exps1...,[*0],Exps2...) = [*0] if all Expi accept [*0]
/// - AndRat(Exps1...,[*0],Exps2...) = 0 if some Expi reject [*0]
/// - AndNLM(Exps1...,1,Exps2...) = AndNLM(Exps1...,Exps2...)
/// - AndNLM(Exps1...,0,Exps2...) = 0
/// - AndNLM(Exps1...,[*0],Exps2...) = AndNLM(Exps1...,Exps2...)
@ -93,8 +96,11 @@ namespace spot
/// - AndNLM(Exps1...,BoolExp1,Exps2...,BoolExp2,Exps3...) =
/// AndNLM(Exps1...,Exps2...,Exps3...,And(BoolExp1,BoolExp2))
/// - Or(Exps1...,1,Exps2...) = 1
/// - Or(Exps1...,0,Exps2...) = And(Exps1...,Exps2...)
/// - Or(Exps1...,0,Exps2...) = Or(Exps1...,Exps2...)
/// - Or(Exp) = Exp
/// - OrRat(Exps1...,0,Exps2...) = OrRat(Exps1...,Exps2...)
/// - OrRat(Exps1...,BoolExp1,Exps2...,BoolExps2...) =
/// OrRat(Exps1...,Exps2...,Or(BoolExp1,BoolExps2...))
/// - Concat(Exps1...,0,Exps2...) = 0
/// - Concat(Exps1...,[*0],Exps2...) = Concat(Exps1...,Exps2...)
/// - Concat(Exp) = Exp
@ -221,6 +227,26 @@ namespace spot
return is_multop(f, multop::And);
}
/// \brief Cast \a f into a multop if it is an AndRat.
///
/// Return 0 otherwise.
inline
multop*
is_AndRat(const formula* f)
{
return is_multop(f, multop::AndRat);
}
/// \brief Cast \a f into a multop if it is an AndNLM.
///
/// Return 0 otherwise.
inline
multop*
is_AndNLM(const formula* f)
{
return is_multop(f, multop::AndNLM);
}
/// \brief Cast \a f into a multop if it is an Or.
///
/// Return 0 otherwise.
@ -231,6 +257,16 @@ namespace spot
return is_multop(f, multop::Or);
}
/// \brief Cast \a f into a multop if it is an OrRat.
///
/// Return 0 otherwise.
inline
multop*
is_OrRat(const formula* f)
{
return is_multop(f, multop::OrRat);
}
/// \brief Cast \a f into a multop if it is a Concat.
///
/// Return 0 otherwise.