diff --git a/src/ltlast/multop.cc b/src/ltlast/multop.cc index 52ace8b3e..85ce20f7c 100644 --- a/src/ltlast/multop.cc +++ b/src/ltlast/multop.cc @@ -118,6 +118,11 @@ namespace spot 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* multop::instance(type op, vec* v) { @@ -149,18 +154,44 @@ namespace spot 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 - // must destroy() any formula we drop. + // must destroy() any formula we drop. Also ignore neutral + // elements and handle absorbent elements. { formula* last = 0; vec::iterator i = v->begin(); while (i != v->end()) { - if (*i == last) + if ((*i == neutral) || (*i == last)) { (*i)->destroy(); i = v->erase(i); } + else if (*i == abs) + { + for (i = v->begin(); i != v->end(); ++i) + (*i)->destroy(); + delete v; + return abs; + } else { last = *i++; @@ -172,15 +203,8 @@ namespace spot if (s == 0) { delete v; - switch (op) - { - case And: - return constant::true_instance(); - case Or: - return constant::false_instance(); - } - /* Unreachable code. */ - assert(0); + assert(neutral != 0); + return neutral; } else if (s == 1) { diff --git a/src/ltltest/equals.test b/src/ltltest/equals.test index 8647b4b86..ad120baa6 100755 --- a/src/ltltest/equals.test +++ b/src/ltltest/equals.test @@ -46,6 +46,10 @@ run 0 ../equals 'a & b' 'b & a & a' run 0 ../equals 'a & b & (c |(f U g)|| e)' \ 'b & a & a & (c | e |(f U g)| e | c) & b' 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 run 1 ../equals 'a' 'b'