Apply ACI rules to multop formulae.

* src/ltlast/multop.cc (instance): Handle neutral and absorbent
elements for the operator.
* src/ltltest/equals.test: Add more tests.
This commit is contained in:
Alexandre Duret-Lutz 2009-12-24 17:46:46 +01:00
parent 4e1a68e676
commit 4fcc4f829c
2 changed files with 39 additions and 11 deletions

View file

@ -118,6 +118,11 @@ namespace spot
multop::map multop::instances; multop::map multop::instances;
// We match equivalent formulae modulo "ACI rules"
// (i.e. associativity, commutativity and idempotence of the
// operator). For instance If `+' designate the OR operator and
// `0' is false (the neutral element for `+') , then `f+f+0' is
// equivalent to `f'.
formula* formula*
multop::instance(type op, vec* v) multop::instance(type op, vec* v)
{ {
@ -149,18 +154,44 @@ namespace spot
std::sort(v->begin(), v->end(), formula_ptr_less_than()); std::sort(v->begin(), v->end(), formula_ptr_less_than());
formula* neutral;
formula* abs;
switch (op)
{
case And:
neutral = constant::true_instance();
abs = constant::false_instance();
break;
case Or:
neutral = constant::false_instance();
abs = constant::true_instance();
break;
default:
neutral = 0;
abs = 0;
break;
}
// Remove duplicates. We can't use std::unique(), because we // Remove duplicates. We can't use std::unique(), because we
// must destroy() any formula we drop. // must destroy() any formula we drop. Also ignore neutral
// elements and handle absorbent elements.
{ {
formula* last = 0; formula* last = 0;
vec::iterator i = v->begin(); vec::iterator i = v->begin();
while (i != v->end()) while (i != v->end())
{ {
if (*i == last) if ((*i == neutral) || (*i == last))
{ {
(*i)->destroy(); (*i)->destroy();
i = v->erase(i); i = v->erase(i);
} }
else if (*i == abs)
{
for (i = v->begin(); i != v->end(); ++i)
(*i)->destroy();
delete v;
return abs;
}
else else
{ {
last = *i++; last = *i++;
@ -172,15 +203,8 @@ namespace spot
if (s == 0) if (s == 0)
{ {
delete v; delete v;
switch (op) assert(neutral != 0);
{ return neutral;
case And:
return constant::true_instance();
case Or:
return constant::false_instance();
}
/* Unreachable code. */
assert(0);
} }
else if (s == 1) else if (s == 1)
{ {

View file

@ -46,6 +46,10 @@ run 0 ../equals 'a & b' 'b & a & a'
run 0 ../equals 'a & b & (c |(f U g)|| e)' \ run 0 ../equals 'a & b & (c |(f U g)|| e)' \
'b & a & a & (c | e |(f U g)| e | c) & b' 'b & a & a & (c | e |(f U g)| e | c) & b'
run 0 ../equals 'a & a' 'a' run 0 ../equals 'a & a' 'a'
run 0 ../equals 'a & a & true' 'a'
run 0 ../equals 'a & false & a' 'false'
run 0 ../equals 'a | false | a' 'a'
run 0 ../equals 'true | a | a' 'true'
# other formulae which are not # other formulae which are not
run 1 ../equals 'a' 'b' run 1 ../equals 'a' 'b'