Commit aec556f7 by Alexandre Duret-Lutz

### Implement basic rewriting rules for {r} and !{r}.

* src/ltlvisit/simplify.cc: Here.
* src/ltltest/reduccmp.test: Test them.
* doc/tl/tl.tex: Document them.
parent d6587cf5
 ... ... @@ -759,16 +759,16 @@ formula $f$ to form another PSL formula. existential suffix implication & $\sere{r}\Esuffix{} f$ \\ closure weak closure & $\sere{r}$ \\ negated closure negated weak closure & $\nsere{r}$ \\ \end{tabular} \end{center} For technical reasons, the negated closure is actually implemented as For technical reasons, the negated weak closure is actually implemented as an operator, even if it is syntactically and semantically equal to the combination of $\NOT$ and $\sere{r}$. ... ... @@ -809,6 +809,8 @@ rewritings are also preformed on output to ease reading. $\AsuffixEQ$ and $\AsuffixALTEQ$ are synonyms in the same way as $\Asuffix$ and $\AsuffixALT$ are. The $\seren{r}$ operator is a \emph{strong closure} operator. \subsection{Trivial Identities (Occur Automatically)} For any PSL formula $f$, any SERE $r$, and any Boolean ... ... @@ -826,8 +828,8 @@ formula $b$, the following rewritings are systematically performed & \nsere{\1} & \equiv \0 \\ \sere{\eword}\Asuffix f&\equiv \1 & \sere{\eword}\Esuffix f&\equiv \0 & \sere{\eword} & \equiv \0 & \nsere{\eword} & \equiv \1 \\ & \sere{\eword} & \equiv \1 & \nsere{\eword} & \equiv \0 \\ \sere{b}\Asuffix f&\equiv (\NOT{b})\OR f & \sere{b}\Esuffix f&\equiv b\AND f & \sere{b} &\equiv b ... ... @@ -1205,7 +1207,7 @@ rewriting arrange any PSL formula into negative normal form. \NOT(f \M g) & \equiv (\NOT f) \W (\NOT g)& \NOT(\sere{r} \Esuffix f) &\equiv \sere{r} \Asuffix \NOT f \end{align*} \noindent Recall the that negated closure $\nsere{r}$ is actually \noindent Recall the that negated weak closure $\nsere{r}$ is actually implemented as a specific operator, so it not actually prefixed by the $\NOT$ operator. \begin{align*} ... ... @@ -1474,6 +1476,22 @@ denoted with $\equiV$ can be disabled by setting the \sere{r_1\OR r_2}\Esuffix f &\equiV (\sere{r_1}\Esuffix f)\OR(\sere{r_2}\Esuffix f) \end{align*} Here are basic the rewritings for the weak closure and its negation: \begin{align*} \sere{r}&\equiv \1\text{~if~}\varepsilon\VDash r& \nsere{r}&\equiv \0\text{~if~}\varepsilon\VDash r\\ \sere{r_1;r_2}&\equiv \sere{r_1}\text{~if~}\varepsilon\VDash r_2& \nsere{r_1;r_2}&\equiv \nsere{r_1}\text{~if~}\varepsilon\VDash r_2\\ \sere{b;r}&\equiV b\AND\X\sere{r}& \nsere{b;r}&\equiV (\NOT b)\OR\X\nsere{r}\\ \sere{b\STAR{};r}&\equiv b\W\sere{r}& \nsere{b\STAR{};r}&\equiv (\NOT b)\M\nsere{r}\\ \sere{b\STAR{\mvar{i}..\mvar{j}};r}&\equiV \underbrace{b\AND \X(b\ldots}_{\mathclap{i\text{~occurences of~}b}}\AND\X\sere{b\STAR{\mvar{0}..\mvar{j-i}}\CONCAT r})& \nsere{b\STAR{\mvar{i}..\mvar{j}};r}&\equiV \underbrace{(\NOT b)\OR \X((\NOT b)\ldots}_{\mathclap{i\text{~occurences of~}\NOT b}}\OR\X\nsere{b\STAR{\mvar{0}..\mvar{j-i}}\CONCAT r}) \\ \sere{b\STAR{\mvar{i}..\mvar{j}}}&\equiV \underbrace{b\AND \X(b\AND \X(\ldots b))}_{i\text{~occurences of~}b}& \nsere{b\STAR{\mvar{i}..\mvar{j}}}&\equiV \underbrace{(\NOT b)\OR \X((\NOT b)\OR \X(\ldots(\NOT b)))}_{i\text{~occurences of~}\NOT b} \end{align*} \subsection{Simplifications for Eventual and Universal Formul\ae} \label{sec:eventunivrew} ... ...
 ... ... @@ -270,13 +270,13 @@ for x in ../reduccmp ../reductaustr; do run 0 $x '{a && {b*;c:e}} <>-> d' 'a & c & d & e' run 0$x '{a && {b;c*}} <>-> d' 'a & b & d' run 0 $x '{a && {b;c*:e}} <>-> d' 'a & b & d & e' run 0$x '{{b1;r1*}&&{b2;r2*}}' '{{b1&&b2};{r1*&&r2*}}' run 0 $x '{{{b1;r1*}&&{b2;r2*}};c}' 'b1&b2&X{{r1*&&r2*};c}' run 0$x '{{b1:r1*}&&{b2:r2*}}' '{{b1&&b2}:{r1*&&r2*}}' run 0 $x '{{r1*;b1}&&{r2*;b2}}' '{{r1*&&r2*};{b1&&b2}}' run 0$x '{{r1*:b1}&&{r2*:b2}}' '{{r1*&&r2*}:{b1&&b2}}' run 0 $x '{{a;b*;c}&&{d;e*}&&{f*;g}&&{h*}}' \ '{{f*;g}&&{h*}&&{{a&&d};{e* && {b*;c}}}}' run 0$x '{{b1;r1*}&{b2;r2*}}' '{{b1&&b2};{r1*&r2*}}' run 0 $x '{{{b1;r1*}&{b2;r2*}};c}' 'b1&b2&X{{r1*&r2*};c}' run 0$x '{{b1:r1*}&{b2:r2*}}' '{{b1&&b2}:{r1*&r2*}}' run 0 $x '{{r1*;b1}&{r2*;b2}}' '{{r1*&r2*};{b1&&b2}}' run 0$x '{{r1*:b1}&{r2*:b2}}' '{{r1*&r2*}:{b1&&b2}}' ... ... @@ -312,6 +312,12 @@ for x in ../reduccmp ../reductaustr; do run 0 $x '{a|b*|c|d*}<>->e' '((a | c) & e) | (e M b) | (e M d)' run 0$x '{{[*0] | a};b;{[*0] | a};c;e[*]} <>-> f' \ '{{[*0] | a};b;{[*0] | a}} <>-> X(c & (f | X(f M e)))' run 0 $x '{a;b[*];c[*];e;f*}' 'a & X(b W (c W e))' run 0$x '{a;b*;(a* && (b;c));c*}' 'a & X(b W {a[*] && {b;c}})' run 0 $x '{a;a;b[*2..];b}' 'a & X(a & X(b & X(b & Xb)))' run 0$x '!{a;a;b[*2..];b}' '!a | X(!a | X(!b | X(!b | X!b)))' run 0 $x '!{a;b[*];c[*];e;f*}' '!a | X(!b M (!c M !e))' run 0$x '!{a;b*;(a* && (b;c));c*}' '!a | X(!b M !{a[*] && {b;c}})' # not reduced run 0 \$x '{a;(b[*2..4];c*;([*0]+{d;e}))*}!' \ ... ...
 ... ... @@ -1038,6 +1038,32 @@ namespace spot } } // if !neg build c&X(c&X(...&X(tail))) with n occurences of c // if neg build !c|X(!c|X(...|X(tail))). formula* dup_b_x_tail(bool neg, formula* c, formula* tail, unsigned n) { c->clone(); multop::type mop; if (neg) { c = unop::instance(unop::Not, c); mop = multop::Or; } else { mop = multop::And; } while (n--) { tail = unop::instance(unop::X, tail); tail = // b&X(tail) or !b|X(tail) multop::instance(mop, c->clone(), tail); } c->destroy(); return tail; } void visit(unop* uo) { ... ... @@ -1256,9 +1282,150 @@ namespace spot && c_->lcc.contained(result_, uo)) return; break; case unop::Finish: case unop::Closure: case unop::NegClosure: // {e} = 1 if e accepts [*0] // !{e} = 0 if e accepts [*0] if (result_->accepts_eword()) { result_->destroy(); result_ = ((op == unop::Closure) ? constant::true_instance() : constant::false_instance()); return; } if (multop* mo = is_Concat(result_)) { unsigned end = mo->size() - 1; // {b₁;b₂;b₃*;e₁;f₁;e₂;f₂;e₂;e₃;e₄} // = b₁&X(b₂&X(b₃ W {e₁;f₁;e₂;f₂})) // !{b₁;b₂;b₃*;e₁;f₁;e₂;f₂;e₂;e₃;e₄} // = !b₁|X(!b₂|X(!b₃ M !{e₁;f₁;e₂;f₂})) // if e denotes a term that accepts [*0] // and b denotes a Boolean formula. while (mo->nth(end)->accepts_eword()) --end; unsigned start = 0; while (start <= end) { formula* r = mo->nth(start); bunop* es = is_KleenStar(r); if ((r->is_boolean() && !opt_.reduce_size_strictly) || (es && es->child()->is_boolean())) ++start; else break; } unsigned s = end + 1 - start; if (s != mo->size()) { multop::vec* v = new multop::vec; v->reserve(s); for (unsigned n = start; n <= end; ++n) v->push_back(mo->nth(n)->clone()); formula* tail = multop::instance(multop::Concat, v); tail = unop::instance(op, tail); bool doneg = op == unop::NegClosure; for (unsigned n = start; n > 0;) { --n; formula* e = mo->nth(n); // {b;f} = b & X{f} // !{b;f} = !b | X!{f} if (e->is_boolean()) { tail = unop::instance(unop::X, tail); e->clone(); if (doneg) tail = multop::instance(multop::Or, unop::instance(unop::Not, e), tail); else tail = multop::instance(multop::And, e, tail); } // {b*;f} = b W {f} // !{b*;f} = !b M !{f} else { bunop* es = is_KleenStar(e); assert(es); formula* c = es->child()->clone(); if (doneg) tail = binop::instance(binop::M, unop::instance(unop::Not, c), tail); else tail = binop::instance(binop::W, c, tail); } } mo->destroy(); result_ = recurse_destroy(tail); return; } // {b[*i..j];c} = b&X(b&X(... b&X{b[*0..j-i];c})) // !{b[*i..j];c} = !b&X(!b&X(... !b&X!{b[*0..j-i];c})) if (!opt_.reduce_size_strictly) if (bunop* s = is_Star(mo->nth(0))) { formula* c = s->child(); unsigned min = s->min(); if (c->is_boolean() && min > 0) { unsigned max = s->max(); if (max != bunop::unbounded) max -= min; unsigned ss = mo->size(); multop::vec* v = new multop::vec; v->reserve(ss); v->push_back(bunop::instance(bunop::Star, c->clone(), 0, max)); for (unsigned n = 1; n < ss; ++n) v->push_back(mo->nth(n)->clone()); formula* tail = multop::instance(multop::Concat, v); tail = // {b[*0..j-i]} or !{b[*0..j-i]} unop::instance(op, tail); tail = dup_b_x_tail(op == unop::NegClosure, c, tail, min); mo->destroy(); result_ = recurse_destroy(tail); return; } } } // {b[*i..j]} = b&X(b&X(... b)) with i occurences of b // !{b[*i..j]} = !b&X(!b&X(... !b)) if (!opt_.reduce_size_strictly) if (bunop* s = is_Star(result_)) { formula* c = s->child(); if (c->is_boolean()) { unsigned min = s->min(); assert(min > 0); formula* tail; if (op == unop::NegClosure) tail = dup_b_x_tail(true, c, constant::false_instance(), min); else tail = dup_b_x_tail(false, c, constant::true_instance(), min); result_->destroy(); result_ = recurse_destroy(tail); return; } } break; case unop::Finish: // No simplification break; } ... ...
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!