introduce op::strong_X

This was prompted by reports by Andrew Wells and Yong Li.

* NEWS, doc/tl/tl.tex: Document the changes.
* THANKS: Add Andrew.
* bin/ltlfilt.cc: Match --ltl before --from-ltlf if needed.
* spot/parsetl/parsedecl.hh, spot/parsetl/parsetl.yy,
spot/parsetl/scantl.ll: Parse X[!].
* spot/tl/formula.cc, spot/tl/formula.hh: Declare the new operator.
* spot/tl/ltlf.cc: Adjust to handle op::X and op::strong_X correctly.
* spot/tl/dot.cc, spot/tl/mark.cc, spot/tl/mutation.cc,
spot/tl/print.cc, spot/tl/simplify.cc, spot/tl/snf.cc,
spot/tl/unabbrev.cc, spot/twa/formula2bdd.cc,
spot/twaalgos/ltl2taa.cc, spot/twaalgos/ltl2tgba_fm.cc,
tests/core/ltlgrind.test, tests/core/rand.test,
tests/core/sugar.test, tests/python/randltl.ipynb: Adjust.
* tests/core/ltlfilt.test, tests/core/sugar.test,
tests/core/utf8.test: More tests.
This commit is contained in:
Alexandre Duret-Lutz 2019-09-22 21:15:55 +02:00
parent b91ba58bbe
commit be389c5c25
26 changed files with 434 additions and 134 deletions

30
NEWS
View file

@ -1,5 +1,35 @@
New in spot 2.8.1.dev (not yet released) New in spot 2.8.1.dev (not yet released)
Library:
- Historically, Spot only supports LTL with infinite semantics
so it had automatic simplifications reducing X(1) and X(0) to
1 and 0 whenever such formulas are constructed. This
caused issues for users of LTLf formulas, where it is important
to distinguish a "weak next" (for which X(1)=1 but X(0)!=0) from
a "strong next" (for which X(0)=0 but X(1)!=1).
To accomodate this, this version introduces a new operator
op::strong_X in addition to the existing op::X (whose
interpretation is now weak in LTLf). The syntax for the strong
next is X[!] as a reference to the PSL syntax (where the strong
next is written X!).
Trivial simplification rules for X are changed to just
X(1) = 1 (and not X(0)=0 anymore)
while we have
X[!]0 = 0
The X(0)=0 and X[!]1=1 reductions are now preformed during LTL
simplification, not automatically. Aside from the from_ltlf()
function, the other functions of the library handle X and X[!] in
the same way, since there is no different between X and X[!] over
infinite words.
Operators F[n:m!] and G[n:m!] are also supported as strong
variants of F[n:m] and G[n:m], but those four are only implemented
as syntactic sugar.
Bugs fixed: Bugs fixed:
- Calling "autfilt --dualize" on an alternating automaton with - Calling "autfilt --dualize" on an alternating automaton with

1
THANKS
View file

@ -2,6 +2,7 @@ We are grateful to these people for their comments, help, or suggestions.
Akim Demaille Akim Demaille
Andreas Tollkötter Andreas Tollkötter
Andrew Wells
Anton Pirogov Anton Pirogov
Ayrat Khalimov Ayrat Khalimov
Cambridge Yang Cambridge Yang

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2018 Laboratoire de Recherche et Développement // Copyright (C) 2012-2019 Laboratoire de Recherche et Développement
// de l'Epita (LRDE). // de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -615,8 +615,14 @@ namespace
if (negate) if (negate)
f = spot::formula::Not(f); f = spot::formula::Not(f);
bool matched = true;
if (from_ltlf) if (from_ltlf)
f = spot::from_ltlf(f, from_ltlf); {
matched &= !ltl || f.is_ltl_formula();
if (matched)
f = spot::from_ltlf(f, from_ltlf);
}
if (remove_x) if (remove_x)
{ {
@ -656,8 +662,6 @@ namespace
if (!opt->excl_ap.empty()) if (!opt->excl_ap.empty())
f = opt->excl_ap.constrain(f); f = opt->excl_ap.constrain(f);
bool matched = true;
matched &= !ltl || f.is_ltl_formula(); matched &= !ltl || f.is_ltl_formula();
matched &= !psl || f.is_psl_formula(); matched &= !psl || f.is_psl_formula();
matched &= !boolean || f.is_boolean(); matched &= !boolean || f.is_boolean();

View file

@ -56,14 +56,18 @@
\DeclareMathOperator{\F}{\texttt{F}} \DeclareMathOperator{\F}{\texttt{F}}
\DeclareMathOperator{\FALT}{\texttt{<>}} \DeclareMathOperator{\FALT}{\texttt{<>}}
\newcommand{\FREP}[1]{\texttt{F[#1]}} \newcommand{\FREP}[1]{\texttt{F[#1]}}
\newcommand{\StrongFREP}[1]{\texttt{F[#1!]}}
\DeclareMathOperator{\G}{\texttt{G}} \DeclareMathOperator{\G}{\texttt{G}}
\DeclareMathOperator{\GALT}{\texttt{[]}} \DeclareMathOperator{\GALT}{\texttt{[]}}
\newcommand{\GREP}[1]{\texttt{G[#1]}} \newcommand{\GREP}[1]{\texttt{G[#1]}}
\newcommand{\StrongGREP}[1]{\texttt{G[#1!]}}
\newcommand{\U}{\mathbin{\texttt{U}}} \newcommand{\U}{\mathbin{\texttt{U}}}
\newcommand{\R}{\mathbin{\texttt{R}}} \newcommand{\R}{\mathbin{\texttt{R}}}
\newcommand{\RALT}{\mathbin{\texttt{V}}} \newcommand{\RALT}{\mathbin{\texttt{V}}}
\DeclareMathOperator{\X}{\texttt{X}} \DeclareMathOperator{\X}{\texttt{X}}
\newcommand{\StrongX}{\texttt{X[!]}}
\newcommand{\XREP}[1]{\texttt{X[#1]}} \newcommand{\XREP}[1]{\texttt{X[#1]}}
\newcommand{\StrongXREP}[1]{\texttt{X[#1!]}}
\DeclareMathOperator{\XALT}{\texttt{()}} \DeclareMathOperator{\XALT}{\texttt{()}}
\newcommand{\M}{\mathbin{\texttt{M}}} \newcommand{\M}{\mathbin{\texttt{M}}}
\newcommand{\W}{\mathbin{\texttt{W}}} \newcommand{\W}{\mathbin{\texttt{W}}}
@ -485,7 +489,8 @@ temporal operators can be used to construct another temporal formula.
& preferred & \multicolumn{1}{c}{other supported} & \multicolumn{2}{l}{UTF8 characters supported} \\ & preferred & \multicolumn{1}{c}{other supported} & \multicolumn{2}{l}{UTF8 characters supported} \\
operator & syntax & \multicolumn{1}{c}{syntaxes} & preferred & others \\ operator & syntax & \multicolumn{1}{c}{syntaxes} & preferred & others \\
\cmidrule(r){1-3} \cmidrule(l){4-5} \cmidrule(r){1-3} \cmidrule(l){4-5}
Next & $\X f$ & $\XALT f$ & $\Circle$ \uni{25CB} & $\Circle$ \uni{25EF}\\ (Weak) Next & $\X f$ & $\XALT f$ & $\Circle$ \uni{25CB} & $\Circle$ \uni{25EF}\\
Strong Next & $\StrongX f$ & & \tikz[baseline=(X.base)]\node[inner sep=0pt, circle, draw](X){\textsc{x}}; \uni{24CD} & \\
Eventually & $\F f$ & $\FALT f$ & $\Diamond$ \uni{25C7} & $\Diamond$ \uni{22C4} \uni{2662}\\ Eventually & $\F f$ & $\FALT f$ & $\Diamond$ \uni{25C7} & $\Diamond$ \uni{22C4} \uni{2662}\\
Always & $\G f$ & $\GALT f$ & $\Square$ \uni{25A1} & $\Square$ \uni{2B1C} \uni{25FB}\\ Always & $\G f$ & $\GALT f$ & $\Square$ \uni{25A1} & $\Square$ \uni{2B1C} \uni{25FB}\\
(Strong) Until & $f \U g$ \\ (Strong) Until & $f \U g$ \\
@ -499,6 +504,7 @@ temporal operators can be used to construct another temporal formula.
\begin{align*} \begin{align*}
\sigma\vDash \X f &\iff \sigma^{1..}\vDash f\\ \sigma\vDash \X f &\iff \sigma^{1..}\vDash f\\
\sigma\vDash \StrongX f &\iff \sigma^{1..}\vDash f\\
\sigma\vDash \F f &\iff \exists i\in \N,\, \sigma^{i..}\vDash f\\ \sigma\vDash \F f &\iff \exists i\in \N,\, \sigma^{i..}\vDash f\\
\sigma\vDash \G f &\iff \forall i\in \N,\, \sigma^{i..}\vDash f\\ \sigma\vDash \G f &\iff \forall i\in \N,\, \sigma^{i..}\vDash f\\
\sigma\vDash f\U g &\iff \exists j\in\N,\, \sigma\vDash f\U g &\iff \exists j\in\N,\,
@ -515,6 +521,11 @@ temporal operators can be used to construct another temporal formula.
\sigma \vDash f\R g &\iff (\sigma \vDash f\M g)\lor(\sigma\vDash \G g) \sigma \vDash f\R g &\iff (\sigma \vDash f\M g)\lor(\sigma\vDash \G g)
\end{align*} \end{align*}
Note that the semantics of $\X$ (weak next) and $\StrongX$ (strong
next) are identical in LTL formulas. The two operators make sense
only to build LTLf formulas (i.e., LTL with finite semantics), for
which support is being progressively introduced in Spot.
Appendix~\ref{sec:ltl-equiv} explains how to rewrite the above LTL Appendix~\ref{sec:ltl-equiv} explains how to rewrite the above LTL
operators using only $\X$ and one operator chosen among $\U$, $\W$, operators using only $\X$ and one operator chosen among $\U$, $\W$,
$\M$,and $\R$. This could be useful to understand the operators $\R$, $\M$,and $\R$. This could be useful to understand the operators $\R$,
@ -537,12 +548,20 @@ or all times between $n$ and $m$ steps.
\GREP{\mvar{n}:\mvar{m}}f \GREP{\mvar{n}:\mvar{m}}f
& \equiv \underbrace{\vphantom{(}\X\X\ldots\X}_{\mathclap{\text{\mvar{n} occ. of~}\X}} (f \AND \underbrace{\X(f \AND \X(\ldots \AND \X f))}_{\mathclap{\mvar{m}-\mvar{n}\text{~occ. of~}\X}}) & \equiv \underbrace{\vphantom{(}\X\X\ldots\X}_{\mathclap{\text{\mvar{n} occ. of~}\X}} (f \AND \underbrace{\X(f \AND \X(\ldots \AND \X f))}_{\mathclap{\mvar{m}-\mvar{n}\text{~occ. of~}\X}})
& \GREP{\mvar{n}:}f &\equiv \XREP{\mvar{n}}\G{}f\\ & \GREP{\mvar{n}:}f &\equiv \XREP{\mvar{n}}\G{}f\\
\StrongXREP{\mvar{n}} f
& \equiv \underbrace{\StrongX\StrongX\ldots\StrongX}_{\mathclap{\text{\mvar{n} occurrences of~}\StrongX}} f \\
\StrongFREP{\mvar{n}:\mvar{m}}f
& \equiv \underbrace{\vphantom{(}\StrongX\StrongX\ldots\StrongX}_{\mathclap{\text{\mvar{n} occ. of~}\StrongX}} (f \OR \underbrace{\StrongX(f \OR \StrongX(\ldots \OR \StrongX f))}_{\mathclap{\mvar{m}-\mvar{n}\text{~occ. of~}\StrongX}})
& \StrongFREP{\mvar{n}:}f &\equiv \StrongXREP{\mvar{n}}\F{}f\\
\StrongGREP{\mvar{n}:\mvar{m}}f
& \equiv \underbrace{\vphantom{(}\StrongX\StrongX\ldots\StrongX}_{\mathclap{\text{\mvar{n} occ. of~}\StrongX}} (f \AND \underbrace{\StrongX(f \AND \StrongX(\ldots \AND \StrongX f))}_{\mathclap{\mvar{m}-\mvar{n}\text{~occ. of~}\StrongX}})
& \StrongGREP{\mvar{n}:}f &\equiv \StrongXREP{\mvar{n}}\G{}f
\end{align*} \end{align*}
\subsection{Trivial Identities (Occur Automatically)} \subsection{Trivial Identities (Occur Automatically)}
\begin{align*} \begin{align*}
\X\0 &\equiv \0 & \StrongX\0 &\equiv \0 &
\F\0 &\equiv \0 & \F\0 &\equiv \0 &
\G\0 &\equiv \0 \\ \G\0 &\equiv \0 \\
\X\1 &\equiv \1 & \X\1 &\equiv \1 &
@ -983,33 +1002,34 @@ operator, even if the operator has multiple synonyms (like \samp{|},
\samp{||}, and {`\verb=\/='}). \samp{||}, and {`\verb=\/='}).
\begin{align*} \begin{align*}
\mathit{constant} ::={} & \0 \mid \1 \\ \mathit{constant} ::={} & \0 \mid \1 \\
\mathit{atomic\_prop} ::={} & \text{see secn~\ref{sec:ap}} \\[1ex] \mathit{atomic\_prop} ::={} & \text{see secn~\ref{sec:ap}} \\[1ex]
\mathit{bformula} ::={} & \mathit{constant} & \mid{} & \tsamp{(}\,\mathit{bformula}\,\tsamp{)} & \mid{} & \mathit{bformula}\,\msamp{\XOR}\,\mathit{bformula} \\ \mathit{bformula} ::={} & \mathit{constant} & \mid{} & \tsamp{(}\,\mathit{bformula}\,\tsamp{)} & \mid{} & \mathit{bformula}\,\msamp{\XOR}\,\mathit{bformula} \\
\mid{} & \mathit{atomic\_prop} & \mid{} & \msamp{\NOT}\,\mathit{bformula} & \mid{} & \mathit{bformula}\,\msamp{\EQUIV}\,\mathit{bformula} \\ \mid{} & \mathit{atomic\_prop} & \mid{} & \msamp{\NOT}\,\mathit{bformula} & \mid{} & \mathit{bformula}\,\msamp{\EQUIV}\,\mathit{bformula} \\
\mid{} & \mathit{atomic\_prop}\code{=0} & \mid{} & \mathit{bformula}\,\msamp{\AND}\,\mathit{bformula} & \mid{} & \mathit{bformula}\,\msamp{\IMPLIES}\,\mathit{bformula} \\ \mid{} & \mathit{atomic\_prop}\code{=0} & \mid{} & \mathit{bformula}\,\msamp{\AND}\,\mathit{bformula} & \mid{} & \mathit{bformula}\,\msamp{\IMPLIES}\,\mathit{bformula} \\
\mid{} & \mathit{atomic\_prop}\code{=1} & \mid{} & \mathit{bformula}\,\msamp{\OR}\,\mathit{bformula} \\[1ex] \mid{} & \mathit{atomic\_prop}\code{=1} & \mid{} & \mathit{bformula}\,\msamp{\OR}\,\mathit{bformula} \\[1ex]
\mathit{sere} ::={} & \mathit{bformula} & \mid{} & \msamp{\STAR{\mvar{i}..\mvar{j}}} & \mid{} & \DELAY{\mvar{i}}\mathit{sere} \\ \mathit{sere} ::={} & \mathit{bformula} & \mid{} & \msamp{\STAR{\mvar{i}..\mvar{j}}} & \mid{} & \DELAY{\mvar{i}}\mathit{sere} \\
\mid{} & \tsamp{\{}\,\mathit{sere}\,\tsamp{\}} & \mid{} & \msamp{\PLUS{}} & \mid{} & \DELAYR{\mvar{i}..\mvar{j}}\mathit{sere} \\ \mid{} & \tsamp{\{}\,\mathit{sere}\,\tsamp{\}} & \mid{} & \msamp{\PLUS{}} & \mid{} & \DELAYR{\mvar{i}..\mvar{j}}\mathit{sere} \\
\mid{} & \tsamp{(}\,\mathit{sere}\,\tsamp{)} & \mid{} & \mathit{sere}\msamp{\STAR{\mvar{i}..\mvar{j}}} & \mid{} & \mathit{sere}\DELAY{\mvar{i}}\mathit{sere} \\ \mid{} & \tsamp{(}\,\mathit{sere}\,\tsamp{)} & \mid{} & \mathit{sere}\msamp{\STAR{\mvar{i}..\mvar{j}}} & \mid{} & \mathit{sere}\DELAY{\mvar{i}}\mathit{sere} \\
\mid{} & \mathit{sere}\msamp{\OR}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\PLUS} & \mid{} & \mathit{sere}\DELAYR{\mvar{i}..\mvar{j}}\mathit{sere} \\ \mid{} & \mathit{sere}\msamp{\OR}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\PLUS} & \mid{} & \mathit{sere}\DELAYR{\mvar{i}..\mvar{j}}\mathit{sere} \\
\mid{} & \mathit{sere}\msamp{\AND}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\FSTAR{\mvar{i}..\mvar{j}}} & \mid{} & \FIRSTMATCH\code(\,sere\,\code) \\ \mid{} & \mathit{sere}\msamp{\AND}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\FSTAR{\mvar{i}..\mvar{j}}} & \mid{} & \FIRSTMATCH\code(\,sere\,\code) \\
\mid{} & \mathit{sere}\msamp{\ANDALT}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\FPLUS} \\ \mid{} & \mathit{sere}\msamp{\ANDALT}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\FPLUS} \\
\mid{} & \mathit{sere}\msamp{\CONCAT}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\EQUAL{\mvar{i}..\mvar{j}}} \\ \mid{} & \mathit{sere}\msamp{\CONCAT}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\EQUAL{\mvar{i}..\mvar{j}}} \\
\mid{} & \mathit{sere}\msamp{\FUSION}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\GOTO{\mvar{i}..\mvar{j}}} \\[1ex] \mid{} & \mathit{sere}\msamp{\FUSION}\mathit{sere} & \mid{} & \mathit{sere}\msamp{\GOTO{\mvar{i}..\mvar{j}}} \\[1ex]
\mathit{tformula} ::={} & \mathit{bformula} & \mid{} & \msamp{\X}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\Asuffix}\,\mathit{tformula} \\ \mathit{tformula} ::={} & \mathit{bformula} & \mid{} & \msamp{\X}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\Asuffix}\,\mathit{tformula} \\
\mid{} & \tsamp{(}\,\mathit{tformula}\,\tsamp{)} & \mid{} & \msamp{\XREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\AsuffixEQ}\,\mathit{tformula} \\ \mid{} & \tsamp{(}\,\mathit{tformula}\,\tsamp{)} & \mid{} & \msamp{\StrongX}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\AsuffixEQ}\,\mathit{tformula} \\
\mid{} & \msamp{\NOT}\,\mathit{tformula}\, & \mid{} & \msamp{\F}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\Esuffix}\,\mathit{tformula} \\ \mid{} & \msamp{\NOT}\,\mathit{tformula}\, & \mid{} & \msamp{\XREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\Esuffix}\,\mathit{tformula} \\
\mid{} & \mathit{tformula}\,\msamp{\AND}\,\mathit{tformula} & \mid{} & \msamp{\FREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\EsuffixEQ}\,\mathit{tformula} \\ \mid{} & \mathit{tformula}\,\msamp{\AND}\,\mathit{tformula} & \mid{} & \msamp{\StrongXREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\,\msamp{\EsuffixEQ}\,\mathit{tformula} \\
\mid{} & \mathit{tformula}\,\msamp{\OR}\,\mathit{tformula} & \mid{} & \msamp{\G}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}} \\ \mid{} & \mathit{tformula}\,\msamp{\OR}\,\mathit{tformula} & \mid{} & \msamp{\F}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}} \\
\mid{} & \mathit{tformula}\,\msamp{\IMPLIES}\,\mathit{tformula} & \mid{} & \msamp{\GREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\msamp{\NOT} \\ \mid{} & \mathit{tformula}\,\msamp{\IMPLIES}\,\mathit{tformula} & \mid{} & \msamp{\FREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} & \mid{} & \tsamp{\{}\mathit{sere}\tsamp{\}}\msamp{\NOT} \\
\mid{} & \mathit{tformula}\,\msamp{\XOR}\,\mathit{tformula} & \mid{} & \mathit{tformula}\,\msamp{\U}\,\mathit{tformula} \\ \mid{} & \mathit{tformula}\,\msamp{\XOR}\,\mathit{tformula} & \mid{} & \msamp{\StrongFREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} \\
\mid{} & \mathit{tformula}\,\msamp{\EQUIV}\,\mathit{tformula} & \mid{} & \mathit{tformula}\,\msamp{\W}\,\mathit{tformula} \\ \mid{} & \mathit{tformula}\,\msamp{\EQUIV}\,\mathit{tformula} & \mid{} & \msamp{\G}\,\mathit{tformula} \\
& & \mid{} & \mathit{tformula}\,\msamp{\R}\,\mathit{tformula} \\ \mid{} & \mathit{tformula}\,\msamp{\U}\,\mathit{tformula} & \mid{} & \msamp{\GREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} \\
& & \mid{} & \mathit{tformula}\,\msamp{\M}\,\mathit{tformula} \\ \mid{} & \mathit{tformula}\,\msamp{\W}\,\mathit{tformula} & \mid{} & \msamp{\StrongGREP{\mvar{i}..\mvar{j}}}\,\mathit{tformula} \\
\mid{} & \mathit{tformula}\,\msamp{\R}\,\mathit{tformula} \\
\mid{} & \mathit{tformula}\,\msamp{\M}\,\mathit{tformula}
\end{align*} \end{align*}
\section{Operator precedence} \section{Operator precedence}
The following operator precedence describes the current parser of The following operator precedence describes the current parser of
@ -1142,6 +1162,7 @@ rules:
\varphi_E ::={}& \0 \varphi_E ::={}& \0
\mid \1 \mid \1
\mid \X \varphi_E \mid \X \varphi_E
\mid \StrongX \varphi_E
\mid \F \varphi \mid \F \varphi
\mid \G \varphi_E \mid \G \varphi_E
\mid \varphi_E\AND \varphi_E \mid \varphi_E\AND \varphi_E
@ -1156,6 +1177,7 @@ rules:
\varphi_U ::={}& \0 \varphi_U ::={}& \0
\mid \1 \mid \1
\mid \X \varphi_U \mid \X \varphi_U
\mid \StrongX \varphi_U
\mid \F \varphi_U \mid \F \varphi_U
\mid \G \varphi \mid \G \varphi
\mid \varphi_U\AND \varphi_U \mid \varphi_U\AND \varphi_U
@ -1450,6 +1472,10 @@ they try to lift subformulas that are both eventual and universal
are applied only when \verb|favor_event_univ|' is \texttt{false}: they are applied only when \verb|favor_event_univ|' is \texttt{false}: they
try to \textit{lower} subformulas that are both eventual and universal. try to \textit{lower} subformulas that are both eventual and universal.
Currently all these simplifications assume LTL semantics, so they make
no differences between $\X$ and $\StrongX$. For simplicity, they are
only listed with $\X$.
\subsection{Basic Simplifications}\label{sec:basic-simp} \subsection{Basic Simplifications}\label{sec:basic-simp}
These simplifications are enabled with These simplifications are enabled with

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2010, 2012, 2013, 2014, 2015 Laboratoire de Recherche et // Copyright (C) 2010, 2012, 2013, 2014, 2015, 2019 Laboratoire de Recherche et
// Développement de l'Epita (LRDE) // Développement de l'Epita (LRDE)
// Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), // Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre // département Systèmes Répartis Coopératifs (SRC), Université Pierre

View file

@ -207,8 +207,10 @@ using namespace spot;
%token OP_U "until operator" OP_R "release operator" %token OP_U "until operator" OP_R "release operator"
%token OP_W "weak until operator" OP_M "strong release operator" %token OP_W "weak until operator" OP_M "strong release operator"
%token OP_F "sometimes operator" OP_G "always operator" %token OP_F "sometimes operator" OP_G "always operator"
%token OP_X "next operator" OP_NOT "not operator" %token OP_X "next operator" OP_STRONG_X "strong next operator"
%token OP_XREP "X[.] operator" OP_FREP "F[.] operator" OP_GREP "G[.] operator" %token OP_NOT "not operator"
%token OP_XREP "X[.] operator"
%token OP_FREP "F[.] operator" OP_GREP "G[.] operator"
%token OP_STAR "star operator" OP_BSTAR "bracket star operator" %token OP_STAR "star operator" OP_BSTAR "bracket star operator"
%token OP_BFSTAR "bracket fusion-star operator" %token OP_BFSTAR "bracket fusion-star operator"
%token OP_PLUS "plus operator" %token OP_PLUS "plus operator"
@ -218,6 +220,7 @@ using namespace spot;
%token OP_EQUAL_OPEN "opening bracket for equal operator" %token OP_EQUAL_OPEN "opening bracket for equal operator"
%token OP_GOTO_OPEN "opening bracket for goto operator" %token OP_GOTO_OPEN "opening bracket for goto operator"
%token OP_SQBKT_CLOSE "closing bracket" %token OP_SQBKT_CLOSE "closing bracket"
%token OP_SQBKT_STRONG_CLOSE "closing !]"
%token <num> OP_SQBKT_NUM "number for square bracket operator" %token <num> OP_SQBKT_NUM "number for square bracket operator"
%token OP_UNBOUNDED "unbounded mark" %token OP_UNBOUNDED "unbounded mark"
%token OP_SQBKT_SEP "separator for square bracket operator" %token OP_SQBKT_SEP "separator for square bracket operator"
@ -261,7 +264,7 @@ using namespace spot;
/* LTL operators. */ /* LTL operators. */
%right OP_U OP_R OP_M OP_W %right OP_U OP_R OP_M OP_W
%precedence OP_F OP_G OP_FREP OP_GREP %precedence OP_F OP_G OP_FREP OP_GREP
%precedence OP_X OP_XREP %precedence OP_X OP_XREP OP_STRONG_X
/* High priority regex operator. */ /* High priority regex operator. */
%precedence OP_BSTAR OP_STAR_OPEN OP_PLUS %precedence OP_BSTAR OP_STAR_OPEN OP_PLUS
@ -887,16 +890,33 @@ subformula: booleanatom
error_list.emplace_back(@1 + @3, error_list.emplace_back(@1 + @3,
"F[n:m] expects two parameters"); "F[n:m] expects two parameters");
} }
| OP_FREP OP_SQBKT_NUM OP_SQBKT_STRONG_CLOSE subformula
%prec OP_FREP
{ $$ = fnode::nested_unop_range(op::strong_X, op::Or, $2, $2, $4);
error_list.emplace_back(@1 + @3,
"F[n:m!] expects two parameters");
}
| OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE | OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
subformula %prec OP_FREP subformula %prec OP_FREP
{ $$ = fnode::nested_unop_range(op::X, op::Or, $2, $4, $6); } { $$ = fnode::nested_unop_range(op::X, op::Or, $2, $4, $6); }
| OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM
OP_SQBKT_STRONG_CLOSE subformula %prec OP_FREP
{ $$ = fnode::nested_unop_range(op::strong_X,
op::Or, $2, $4, $6); }
| OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE | OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
subformula %prec OP_FREP subformula %prec OP_FREP
{ $$ = fnode::nested_unop_range(op::X, op::Or, $2, { $$ = fnode::nested_unop_range(op::X, op::Or, $2,
fnode::unbounded(), $5); } fnode::unbounded(), $5); }
| OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_STRONG_CLOSE
subformula %prec OP_FREP
{ $$ = fnode::nested_unop_range(op::strong_X, op::Or, $2,
fnode::unbounded(), $5); }
| OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE | OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
error error
{ missing_right_op($$, @1 + @5, "F[.] operator"); } { missing_right_op($$, @1 + @5, "F[.] operator"); }
| OP_FREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM
OP_SQBKT_STRONG_CLOSE error
{ missing_right_op($$, @1 + @5, "F[.!] operator"); }
| OP_FREP error_opt END_OF_INPUT | OP_FREP error_opt END_OF_INPUT
{ error_list.emplace_back(@$, "missing closing bracket for F[.]"); { error_list.emplace_back(@$, "missing closing bracket for F[.]");
$$ = fnode::ff(); } $$ = fnode::ff(); }
@ -904,6 +924,10 @@ subformula: booleanatom
{ error_list.emplace_back(@1 + @3, { error_list.emplace_back(@1 + @3,
"treating this F[.] as a simple F"); "treating this F[.] as a simple F");
$$ = fnode::unop(op::F, $4); } $$ = fnode::unop(op::F, $4); }
| OP_FREP error OP_SQBKT_STRONG_CLOSE subformula %prec OP_FREP
{ error_list.emplace_back(@1 + @3,
"treating this F[.!] as a simple F");
$$ = fnode::unop(op::F, $4); }
| OP_G subformula | OP_G subformula
{ $$ = fnode::unop(op::G, $2); } { $$ = fnode::unop(op::G, $2); }
| OP_G error | OP_G error
@ -911,18 +935,36 @@ subformula: booleanatom
| OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE | OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
subformula %prec OP_GREP subformula %prec OP_GREP
{ $$ = fnode::nested_unop_range(op::X, op::And, $2, $4, $6); } { $$ = fnode::nested_unop_range(op::X, op::And, $2, $4, $6); }
| OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM
OP_SQBKT_STRONG_CLOSE subformula %prec OP_GREP
{ $$ = fnode::nested_unop_range(op::strong_X, op::And,
$2, $4, $6); }
| OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE | OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_CLOSE
subformula %prec OP_GREP subformula %prec OP_GREP
{ $$ = fnode::nested_unop_range(op::X, op::And, $2, { $$ = fnode::nested_unop_range(op::X, op::And, $2,
fnode::unbounded(), $5); } fnode::unbounded(), $5); }
| OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP_unbounded OP_SQBKT_STRONG_CLOSE
subformula %prec OP_GREP
{ $$ = fnode::nested_unop_range(op::strong_X, op::And, $2,
fnode::unbounded(), $5); }
| OP_GREP OP_SQBKT_NUM OP_SQBKT_CLOSE subformula %prec OP_GREP | OP_GREP OP_SQBKT_NUM OP_SQBKT_CLOSE subformula %prec OP_GREP
{ $$ = fnode::nested_unop_range(op::X, op::And, $2, $2, $4); { $$ = fnode::nested_unop_range(op::X, op::And, $2, $2, $4);
error_list.emplace_back(@1 + @3, error_list.emplace_back(@1 + @3,
"G[n:m] expects two parameters"); "G[n:m] expects two parameters");
} }
| OP_GREP OP_SQBKT_NUM OP_SQBKT_STRONG_CLOSE subformula
%prec OP_GREP
{ $$ = fnode::nested_unop_range(op::strong_X, op::And,
$2, $2, $4);
error_list.emplace_back(@1 + @3,
"G[n:m!] expects two parameters");
}
| OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE | OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM OP_SQBKT_CLOSE
error error
{ missing_right_op($$, @1 + @5, "G[.] operator"); } { missing_right_op($$, @1 + @5, "G[.] operator"); }
| OP_GREP OP_SQBKT_NUM OP_SQBKT_SEP OP_SQBKT_NUM
OP_SQBKT_STRONG_CLOSE error
{ missing_right_op($$, @1 + @5, "G[.!] operator"); }
| OP_GREP error_opt END_OF_INPUT | OP_GREP error_opt END_OF_INPUT
{ error_list.emplace_back(@$, "missing closing bracket for G[.]"); { error_list.emplace_back(@$, "missing closing bracket for G[.]");
$$ = fnode::ff(); } $$ = fnode::ff(); }
@ -930,10 +972,18 @@ subformula: booleanatom
{ error_list.emplace_back(@1 + @3, { error_list.emplace_back(@1 + @3,
"treating this G[.] as a simple G"); "treating this G[.] as a simple G");
$$ = fnode::unop(op::F, $4); } $$ = fnode::unop(op::F, $4); }
| OP_GREP error OP_SQBKT_STRONG_CLOSE subformula %prec OP_GREP
{ error_list.emplace_back(@1 + @3,
"treating this G[.!] as a simple G");
$$ = fnode::unop(op::F, $4); }
| OP_X subformula | OP_X subformula
{ $$ = fnode::unop(op::X, $2); } { $$ = fnode::unop(op::X, $2); }
| OP_X error | OP_X error
{ missing_right_op($$, @1, "next operator"); } { missing_right_op($$, @1, "next operator"); }
| OP_STRONG_X subformula
{ $$ = fnode::unop(op::strong_X, $2); }
| OP_STRONG_X error
{ missing_right_op($$, @1, "strong next operator"); }
| OP_XREP OP_SQBKT_NUM OP_SQBKT_CLOSE subformula %prec OP_XREP | OP_XREP OP_SQBKT_NUM OP_SQBKT_CLOSE subformula %prec OP_XREP
{ $$ = fnode::nested_unop_range(op::X, op::Or, $2, $2, $4); } { $$ = fnode::nested_unop_range(op::X, op::Or, $2, $2, $4); }
| OP_XREP OP_SQBKT_NUM OP_SQBKT_CLOSE error | OP_XREP OP_SQBKT_NUM OP_SQBKT_CLOSE error
@ -941,6 +991,15 @@ subformula: booleanatom
| OP_XREP error OP_SQBKT_CLOSE subformula %prec OP_XREP | OP_XREP error OP_SQBKT_CLOSE subformula %prec OP_XREP
{ error_list.emplace_back(@$, "treating this X[.] as a simple X"); { error_list.emplace_back(@$, "treating this X[.] as a simple X");
$$ = fnode::unop(op::X, $4); } $$ = fnode::unop(op::X, $4); }
| OP_XREP OP_SQBKT_STRONG_CLOSE subformula %prec OP_XREP
{ $$ = fnode::unop(op::strong_X, $3); }
| OP_XREP OP_SQBKT_NUM OP_SQBKT_STRONG_CLOSE subformula
%prec OP_XREP
{ $$ = fnode::nested_unop_range(op::strong_X,
op::Or, $2, $2, $4); }
| OP_XREP error OP_SQBKT_STRONG_CLOSE subformula %prec OP_XREP
{ error_list.emplace_back(@$, "treating this X[.!] as a simple X[!]");
$$ = fnode::unop(op::strong_X, $4); }
| OP_XREP error_opt END_OF_INPUT | OP_XREP error_opt END_OF_INPUT
{ error_list.emplace_back(@$, "missing closing bracket for X[.]"); { error_list.emplace_back(@$, "missing closing bracket for X[.]");
$$ = fnode::ff(); } $$ = fnode::ff(); }

View file

@ -64,6 +64,7 @@ DARROWL "=>"|"⇒"|"⟹"
ARROWLR "<->"|"<-->"|"↔" ARROWLR "<->"|"<-->"|"↔"
DARROWLR "<=>"|"⇔" DARROWLR "<=>"|"⇔"
CIRCLE "()"|"○"|"◯" CIRCLE "()"|"○"|"◯"
CIRCLEX "Ⓧ"
NOT "!"|"~"|"¬" NOT "!"|"~"|"¬"
BOXARROW {BOX}{ARROWL}|"|"{ARROWL}|"↦" BOXARROW {BOX}{ARROWL}|"|"{ARROWL}|"↦"
BOXDARROW {BOX}{DARROWL}|"|"{DARROWL}|"⤇" BOXDARROW {BOX}{DARROWL}|"|"{DARROWL}|"⤇"
@ -254,6 +255,7 @@ eol2 (\n\r)+|(\r\n)+
"[=" BEGIN(sqbracket); return token::OP_EQUAL_OPEN; "[=" BEGIN(sqbracket); return token::OP_EQUAL_OPEN;
"["{ARROWL} BEGIN(sqbracket); return token::OP_GOTO_OPEN; "["{ARROWL} BEGIN(sqbracket); return token::OP_GOTO_OPEN;
<sqbracket>"]" BEGIN(0); return token::OP_SQBKT_CLOSE; <sqbracket>"]" BEGIN(0); return token::OP_SQBKT_CLOSE;
<sqbracket>"!]" BEGIN(0); return token::OP_SQBKT_STRONG_CLOSE;
<sqbracket>[0-9]+ { <sqbracket>[0-9]+ {
errno = 0; errno = 0;
unsigned long n = strtoul(yytext, 0, 10); unsigned long n = strtoul(yytext, 0, 10);
@ -313,6 +315,7 @@ eol2 (\n\r)+|(\r\n)+
"U" BEGIN(0); return token::OP_U; "U" BEGIN(0); return token::OP_U;
"R"|"V" BEGIN(0); return token::OP_R; "R"|"V" BEGIN(0); return token::OP_R;
"X"|{CIRCLE} BEGIN(0); return token::OP_X; "X"|{CIRCLE} BEGIN(0); return token::OP_X;
{CIRCLEX} BEGIN(0); return token::OP_STRONG_X;
"W" BEGIN(0); return token::OP_W; "W" BEGIN(0); return token::OP_W;
"M" BEGIN(0); return token::OP_M; "M" BEGIN(0); return token::OP_M;

View file

@ -76,6 +76,7 @@ namespace spot
case op::ap: case op::ap:
case op::Not: case op::Not:
case op::X: case op::X:
case op::strong_X:
case op::F: case op::F:
case op::G: case op::G:
case op::Closure: case op::Closure:

View file

@ -242,6 +242,7 @@ namespace spot
C(Star); C(Star);
C(FStar); C(FStar);
C(first_match); C(first_match);
C(strong_X);
#undef C #undef C
} }
SPOT_UNREACHABLE(); SPOT_UNREACHABLE();
@ -788,10 +789,20 @@ namespace spot
} }
break; break;
} }
case op::X: case op::X:
// X(1) = 1, X(0) = 0 // X(1) = 1
if (f->is_tt() || f->is_ff()) if (f->is_tt())
return f; return f;
// We do not have X(0)=0 because that
// is not true with finite semantics.
assert(!f->is_eword());
break;
case op::strong_X:
// X[!](0) = 0
if (f->is_ff())
return f;
// Note: with finite semantics X[!](1)≠1.
assert(!f->is_eword()); assert(!f->is_eword());
break; break;
@ -1176,6 +1187,7 @@ namespace spot
is_.accepting_eword = false; is_.accepting_eword = false;
break; break;
case op::X: case op::X:
case op::strong_X:
props = children[0]->props; props = children[0]->props;
is_.not_marked = true; is_.not_marked = true;
is_.boolean = false; is_.boolean = false;
@ -1186,6 +1198,10 @@ namespace spot
// is_.syntactic_obligation inherited // is_.syntactic_obligation inherited
// is_.syntactic_recurrence inherited // is_.syntactic_recurrence inherited
// is_.syntactic_persistence inherited // is_.syntactic_persistence inherited
// is_.accepting_eword is currently unused outside SEREs, but
// we could make sense of it if we start supporting LTL over
// finite traces.
is_.accepting_eword = false; is_.accepting_eword = false;
break; break;
case op::F: case op::F:

View file

@ -57,8 +57,22 @@
#include <cstddef> #include <cstddef>
#include <limits> #include <limits>
// The strong_X operator was introduced in Spot 2.8.2 to fix an issue
// with from_ltlf(). As adding a new operator is a backward
// incompatibility, causing new warnings from the compiler.
#if defined(SPOT_BUILD) or defined(SPOT_USES_STRONG_X)
// Use #if SPOT_HAS_STRONG_X in code that need to be backward
// compatible with older Spot versions.
# define SPOT_HAS_STRONG_X 1
// You me #define SPOT_WANT_STRONG_X yourself before including
// this file to force the use of STRONG_X
# define SPOT_WANT_STRONG_X 1
#endif
namespace spot namespace spot
{ {
/// \ingroup tl_essentials /// \ingroup tl_essentials
/// \brief Operator types /// \brief Operator types
enum class op: uint8_t enum class op: uint8_t
@ -98,6 +112,9 @@ namespace spot
Star, ///< Star Star, ///< Star
FStar, ///< Fustion Star FStar, ///< Fustion Star
first_match, ///< first_match(sere) first_match, ///< first_match(sere)
#ifdef SPOT_WANT_STRONG_X
strong_X, ///< strong Next
#endif
}; };
#ifndef SWIG #ifndef SWIG
@ -899,6 +916,22 @@ namespace spot
return nested_unop_range(op::X, op::Or /* unused */, level, level, f); return nested_unop_range(op::X, op::Or /* unused */, level, level, f);
} }
#if SPOT_WANT_STRONG_X
/// \brief Construct a strong_X
/// @{
SPOT_DEF_UNOP(strong_X);
/// @}
/// \brief Construct a strong_X[n]
///
/// strong_X[3]f = strong_X strong_X strong_X f
static formula strong_X(unsigned level, const formula& f)
{
return nested_unop_range(op::strong_X, op::Or /* unused */,
level, level, f);
}
#endif
/// \brief Construct an F /// \brief Construct an F
/// @{ /// @{
SPOT_DEF_UNOP(F); SPOT_DEF_UNOP(F);
@ -1662,6 +1695,9 @@ namespace spot
return *this; return *this;
case op::Not: case op::Not:
case op::X: case op::X:
#if SPOT_HAS_STRONG_X
case op::strong_X:
#endif
case op::F: case op::F:
case op::G: case op::G:
case op::Closure: case op::Closure:

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2016, 2018 Laboratoire de Recherche et Développement // Copyright (C) 2016, 2018, 2019 Laboratoire de Recherche et
// de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -29,11 +29,12 @@ namespace spot
auto t = [&alive] (formula f) { return from_ltlf_aux(f, alive); }; auto t = [&alive] (formula f) { return from_ltlf_aux(f, alive); };
switch (auto o = f.kind()) switch (auto o = f.kind())
{ {
case op::X: case op::strong_X:
case op::F: case op::F:
return formula::unop(o, formula::And({alive, t(f[0])})); return formula::unop(o, formula::And({alive, t(f[0])}));
case op::X: // weak
case op::G: case op::G:
return formula::G(formula::Or({formula::Not(alive), t(f[0])})); return formula::unop(o, formula::Or({formula::Not(alive), t(f[0])}));
// Note that the t() function given in the proof of Theorem 1 of // Note that the t() function given in the proof of Theorem 1 of
// the IJCAI'13 paper by De Giacomo & Vardi has a typo. // the IJCAI'13 paper by De Giacomo & Vardi has a typo.
// t(a U b) should be equal to t(a) U t(b & alive). // t(a U b) should be equal to t(a) U t(b & alive).

View file

@ -42,6 +42,7 @@ namespace spot
case op::ap: case op::ap:
case op::Not: case op::Not:
case op::X: case op::X:
case op::strong_X:
case op::F: case op::F:
case op::G: case op::G:
case op::Closure: case op::Closure:
@ -109,6 +110,7 @@ namespace spot
case op::ap: case op::ap:
case op::Not: case op::Not:
case op::X: case op::X:
case op::strong_X:
case op::F: case op::F:
case op::G: case op::G:
case op::Closure: case op::Closure:

View file

@ -81,6 +81,7 @@ namespace spot
return f; return f;
case op::Not: case op::Not:
case op::X: case op::X:
case op::strong_X:
case op::F: case op::F:
case op::G: case op::G:
case op::first_match: case op::first_match:

View file

@ -72,6 +72,7 @@ namespace spot
KEqualBunop, KEqualBunop,
KGotoBunop, KGotoBunop,
KFirstMatch, KFirstMatch,
KStrongX,
}; };
const char* spot_kw[] = { const char* spot_kw[] = {
@ -112,6 +113,7 @@ namespace spot
"[=", "[=",
"[->", "[->",
"first_match", "first_match",
"X[!]",
}; };
const char* spin_kw[] = { const char* spin_kw[] = {
@ -138,60 +140,62 @@ namespace spot
" || ", " || ",
" || ", " || ",
" && ", " && ",
" && ", // not supported " && ", // not supported
" & ", // not supported " & ", // not supported
";", // not supported ";", // not supported
":", // not supported ":", // not supported
"{", // not supported "{", // not supported
"}", // not supported "}", // not supported
"]", // not supported "]", // not supported
"[*", // not supported "[*", // not supported
"[+]", // not supported "[+]", // not supported
"[:*", // not supported "[:*", // not supported
"[:+]", // not supported "[:+]", // not supported
"[=", // not supported "[=", // not supported
"[->", // not supported "[->", // not supported
"first_match", // not supported "first_match", // not supported
"!X!",
}; };
const char* wring_kw[] = { const char* wring_kw[] = {
"FALSE", "FALSE",
"TRUE", "TRUE",
"[*0]", // not supported "[*0]", // not supported
" ^ ", " ^ ",
" -> ", " -> ",
" <-> ", " <-> ",
" U ", " U ",
" R ", " R ",
" W ", // rewritten " W ", // rewritten
" M ", // rewritten " M ", // rewritten
"<>-> ", // not supported "<>-> ", // not supported
"<>=> ", // not supported "<>=> ", // not supported
"<>+> ", // not supported "<>+> ", // not supported
"<>=+> ", // not supported "<>=+> ", // not supported
"[]-> ", // not supported "[]-> ", // not supported
"[]=> ", // not supported "[]=> ", // not supported
"!", "!",
"X", "X",
"F", "F",
"G", "G",
" + ", " + ",
" | ", // not supported " | ", // not supported
" * ", " * ",
" && ", // not supported " && ", // not supported
" & ", // not supported " & ", // not supported
";", // not supported ";", // not supported
":", // not supported ":", // not supported
"{", // not supported "{", // not supported
"}", // not supported "}", // not supported
"]", // not supported "]", // not supported
"[*", // not supported "[*", // not supported
"[+]", // not supported "[+]", // not supported
"[:*", // not supported "[:*", // not supported
"[:+]", // not supported "[:+]", // not supported
"[=", // not supported "[=", // not supported
"[->", // not supported "[->", // not supported
"first_match", // not supported "first_match", // not supported
"X[!]", // not supported, FIXME: we need a syntax
}; };
const char* utf8_kw[] = { const char* utf8_kw[] = {
@ -232,6 +236,7 @@ namespace spot
"[=", "[=",
"[->", "[->",
"first_match", "first_match",
"",
}; };
const char* latex_kw[] = { const char* latex_kw[] = {
@ -272,6 +277,7 @@ namespace spot
"\\SereEqual{", "\\SereEqual{",
"\\SereGoto{", "\\SereGoto{",
"\\FirstMatch", "\\FirstMatch",
"\\StrongX",
}; };
const char* sclatex_kw[] = { const char* sclatex_kw[] = {
@ -316,6 +322,7 @@ namespace spot
"^{=", "^{=",
"^{\\to", "^{\\to",
"\\mathsf{first\\_match}", "\\mathsf{first\\_match}",
"\\textcircled{\\mathsf{X}}",
}; };
static bool static bool
@ -519,7 +526,18 @@ namespace spot
break; break;
} }
case op::X: case op::X:
emit(KX); {
emit(KX);
bool cst = f[0].is_constant();
if (cst)
openp();
visit(f[0]);
if (cst)
closep();
break;
}
case op::strong_X:
emit(KStrongX);
visit(f[0]); visit(f[0]);
break; break;
case op::F: case op::F:
@ -1076,6 +1094,9 @@ namespace spot
case op::X: case op::X:
os_ << 'X'; os_ << 'X';
break; break;
case op::strong_X:
os_ << 'X'; // unsupported
break;
case op::F: case op::F:
os_ << 'F'; os_ << 'F';
break; break;

View file

@ -489,7 +489,13 @@ namespace spot
result = negated ? formula::Not(f) : f; result = negated ? formula::Not(f) : f;
break; break;
case op::X: case op::X:
// !Xa == X!a case op::strong_X:
// Currently we don't distinguish between weak and
// strong semantics, so we treat the two operators
// identically.
//
// !Xa == X!a
// !X[!]a = X!a
result = formula::X(rec(f[0], negated)); result = formula::X(rec(f[0], negated));
break; break;
case op::F: case op::F:
@ -714,7 +720,10 @@ namespace spot
formula formula
unop_multop(op uop, op mop, vec v) unop_multop(op uop, op mop, vec v)
{ {
return formula::unop(uop, formula::multop(mop, v)); formula f = formula::unop(uop, formula::multop(mop, v));
if (f.is(op::X) && f[0].is_ff())
return formula::ff();
return f;
} }
formula formula
@ -797,6 +806,7 @@ namespace spot
switch (f.kind()) switch (f.kind())
{ {
case op::X: case op::X:
case op::strong_X:
if (res_X && !eu) if (res_X && !eu)
{ {
res_X->emplace_back(f[0]); res_X->emplace_back(f[0]);
@ -950,8 +960,15 @@ namespace spot
case op::FStar: case op::FStar:
return f; return f;
case op::X: case op::X:
case op::strong_X:
{ {
formula c = f[0]; formula c = f[0];
// The following rules are not trivial simplifications,
// because they are not true in LTLf.
// X(0)=0
// X[!](1)=1
if (c.is_constant())
return c;
// Xf = f if f is both eventual and universal. // Xf = f if f is both eventual and universal.
if (c.is_universal() && c.is_eventual()) if (c.is_universal() && c.is_eventual())
{ {
@ -3731,9 +3748,10 @@ namespace spot
switch (f.kind()) switch (f.kind())
{ {
case op::X: case op::X:
case op::strong_X:
if (g.is_eventual() && syntactic_implication(f[0], g)) if (g.is_eventual() && syntactic_implication(f[0], g))
return true; return true;
if (g.is(op::X) && syntactic_implication(f[0], g[0])) if (g.is(op::X, op::strong_X) && syntactic_implication(f[0], g[0]))
return true; return true;
break; break;
@ -3893,6 +3911,7 @@ namespace spot
case op::G: case op::G:
case op::X: case op::X:
case op::strong_X:
if (f.is_universal() && syntactic_implication(f, g[0])) if (f.is_universal() && syntactic_implication(f, g[0]))
return true; return true;
break; break;

View file

@ -103,6 +103,7 @@ namespace spot
case op::ap: case op::ap:
case op::Not: case op::Not:
case op::X: case op::X:
case op::strong_X:
case op::F: case op::F:
case op::G: case op::G:
case op::Closure: case op::Closure:

View file

@ -97,6 +97,7 @@ namespace spot
case op::ap: case op::ap:
case op::Not: case op::Not:
case op::X: case op::X:
case op::strong_X:
case op::Closure: case op::Closure:
case op::NegClosure: case op::NegClosure:
case op::NegClosureMarked: case op::NegClosureMarked:

View file

@ -84,6 +84,7 @@ namespace spot
case op::F: case op::F:
case op::G: case op::G:
case op::X: case op::X:
case op::strong_X:
case op::Closure: case op::Closure:
case op::NegClosure: case op::NegClosure:
case op::NegClosureMarked: case op::NegClosureMarked:

View file

@ -81,6 +81,7 @@ namespace spot
return; return;
} }
case op::X: case op::X:
case op::strong_X:
{ {
ltl2taa_visitor v = recurse(f[0]); ltl2taa_visitor v = recurse(f[0]);
std::vector<formula> dst; std::vector<formula> dst;

View file

@ -585,6 +585,7 @@ namespace spot
case op::F: case op::F:
case op::G: case op::G:
case op::X: case op::X:
case op::strong_X:
case op::Closure: case op::Closure:
case op::NegClosure: case op::NegClosure:
case op::NegClosureMarked: case op::NegClosureMarked:
@ -1215,6 +1216,7 @@ namespace spot
return bdd_not(recurse(node[0])); return bdd_not(recurse(node[0]));
} }
case op::X: case op::X:
case op::strong_X:
{ {
// r(Xy) = Next[y] // r(Xy) = Next[y]
// r(X(a&b&c)) = Next[a]&Next[b]&Next[c] // r(X(a&b&c)) = Next[a]&Next[b]&Next[c]

View file

@ -48,6 +48,8 @@ G(a & Xb)
Xa Xa
F(a & !Xa & Xb) F(a & !Xa & Xb)
{a & {b|c} } {a & {b|c} }
((a && b) U (! (X 1)))
((a && b) U (! (X[!] 1)))
{a[=2:3]}|->b {a[=2:3]}|->b
{a[->2:3]}|->b {a[->2:3]}|->b
@ -63,6 +65,7 @@ EOF
checkopt --boolean <<EOF checkopt --boolean <<EOF
a & (b | c) a & (b | c)
0
EOF EOF
checkopt --bsize-min=2 --bsize-max=4 <<EOF checkopt --bsize-min=2 --bsize-max=4 <<EOF
@ -81,6 +84,8 @@ F(GFa | Gb)
F(b W GFa) F(b W GFa)
a U Fb a U Fb
F(a & !Xa & Xb) F(a & !Xa & Xb)
0
(a & b) U !X[!]1
EOF EOF
checkopt --universal <<EOF checkopt --universal <<EOF
@ -88,16 +93,19 @@ GFa | FGb
F(GFa | Gb) F(GFa | Gb)
GFa | Gb GFa | Gb
G(a & Xb) G(a & Xb)
0
EOF EOF
checkopt --eventual --universal <<EOF checkopt --eventual --universal <<EOF
GFa | FGb GFa | FGb
F(GFa | Gb) F(GFa | Gb)
0
EOF EOF
checkopt --suspendable <<EOF checkopt --suspendable <<EOF
GFa | FGb GFa | FGb
F(GFa | Gb) F(GFa | Gb)
0
EOF EOF
checkopt --stutter-invariant <<EOF checkopt --stutter-invariant <<EOF
@ -110,6 +118,8 @@ b W GFa
a U Fb a U Fb
F(a & !Xa & Xb) F(a & !Xa & Xb)
a & (b | c) a & (b | c)
0
(a & b) U !X[!]1
{{!a}[*];a[+]}[]-> b {{!a}[*];a[+]}[]-> b
{a[*];{!a}[*];a[*]}[]-> b {a[*];{!a}[*];a[*]}[]-> b
{a[*];{!a}[+];a[*]}[]-> b {a[*];{!a}[+];a[*]}[]-> b
@ -120,7 +130,7 @@ a & (b | c)
EOF EOF
checkopt -c --stutter-invariant <<EOF checkopt -c --stutter-invariant <<EOF
16 18
EOF EOF
checkopt --syntactic-stutter-invariant <<EOF checkopt --syntactic-stutter-invariant <<EOF
@ -131,6 +141,7 @@ GFa | Gb
b W GFa b W GFa
a U Fb a U Fb
a & (b | c) a & (b | c)
0
{{!a}[*];a[+]}[]-> b {{!a}[*];a[+]}[]-> b
{a[*];{!a}[*];a[*]}[]-> b {a[*];{!a}[*];a[*]}[]-> b
{a[*];{!a}[+];a[*]}[]-> b {a[*];{!a}[+];a[*]}[]-> b
@ -152,6 +163,8 @@ G(a & Xb)
Xa Xa
F(a & X(!a & b)) F(a & X(!a & b))
a & (b | c) a & (b | c)
0
0
a R (!a | X({a[->1..2]}[]-> (b & X(b W a)))) a R (!a | X({a[->1..2]}[]-> (b & X(b W a))))
a R (!a | X({a[->1..2]}[]-> b)) a R (!a | X({a[->1..2]}[]-> b))
a R (b W !a) a R (b W !a)
@ -169,6 +182,7 @@ F(GFa | Gb)
F(b W GFa) F(b W GFa)
Fb Fb
F(a & X(!a & b)) F(a & X(!a & b))
0
EOF EOF
checkopt --liveness <<EOF checkopt --liveness <<EOF
@ -186,6 +200,8 @@ checkopt --safety <<EOF
G(a & Xb) G(a & Xb)
Xa Xa
a & (b | c) a & (b | c)
0
(a & b) U !X[!]1
{a[=2..3]}[]-> b {a[=2..3]}[]-> b
{a[->2..3]}[]-> b {a[->2..3]}[]-> b
{{!a}[*];a[+]}[]-> b {{!a}[*];a[+]}[]-> b
@ -206,6 +222,8 @@ G(a & Xb)
Xa Xa
F(a & !Xa & Xb) F(a & !Xa & Xb)
a & (b | c) a & (b | c)
0
(a & b) U !X[!]1
{a[=2..3]}[]-> b {a[=2..3]}[]-> b
{a[->2..3]}[]-> b {a[->2..3]}[]-> b
{{!a}[*];a[+]}[]-> b {{!a}[*];a[+]}[]-> b
@ -224,6 +242,8 @@ a U Fb
Xa Xa
F(a & !Xa & Xb) F(a & !Xa & Xb)
a & (b | c) a & (b | c)
0
(a & b) U !X[!]1
EOF EOF
checkopt -v --ltl <<EOF checkopt -v --ltl <<EOF
@ -251,6 +271,8 @@ a U Fb
G(a & Xb) G(a & Xb)
Xa Xa
F(a & !Xa & Xb) F(a & !Xa & Xb)
0
(a & b) U !X[!]1
{a[=2..3]}[]-> b {a[=2..3]}[]-> b
{a[->2..3]}[]-> b {a[->2..3]}[]-> b
{{!a}[*];a[+]}[]-> b {{!a}[*];a[+]}[]-> b
@ -273,6 +295,7 @@ a U Fb
G(a & Xb) G(a & Xb)
F(a & !Xa & Xb) F(a & !Xa & Xb)
a & (b | c) a & (b | c)
(a & b) U !X[!]1
{a[=2..3]}[]-> b {a[=2..3]}[]-> b
{a[->2..3]}[]-> b {a[->2..3]}[]-> b
{{!a}[*];a[+]}[]-> b {{!a}[*];a[+]}[]-> b
@ -300,10 +323,6 @@ F(GFa | Gb)
F(b W GFa) F(b W GFa)
EOF EOF
# Restrict to LTL
run 0 ltlfilt --ltl formulas > formulas2
mv formulas2 formulas
checkopt --ltl --from-ltlf=al <<EOF checkopt --ltl --from-ltlf=al <<EOF
al & (G(!al | F(a & al)) | F(al & G(!al | b))) & (al U G!al) al & (G(!al | F(a & al)) | F(al & G(!al | b))) & (al U G!al)
al & F(al & (G(!al | F(a & al)) | G(!al | b))) & (al U G!al) al & F(al & (G(!al | F(a & al)) | G(!al | b))) & (al U G!al)
@ -311,10 +330,12 @@ al & F(al & ((!al | b) W G(!al | F(a & al)))) & (al U G!al)
al & (G(!al | F(a & al)) | G(!al | b)) & (al U G!al) al & (G(!al | F(a & al)) | G(!al | b)) & (al U G!al)
al & ((!al | b) W G(!al | F(a & al))) & (al U G!al) al & ((!al | b) W G(!al | F(a & al))) & (al U G!al)
al & (a U (al & F(al & b))) & (al U G!al) al & (a U (al & F(al & b))) & (al U G!al)
al & G(!al | (a & X(al & b))) & (al U G!al) al & G(!al | (a & X(!al | b))) & (al U G!al)
al & X(a & al) & (al U G!al) al & X(a | !al) & (al U G!al)
al & F(a & al & !X(a & al) & X(al & b)) & (al U G!al) al & F(a & al & !X(a | !al) & X(!al | b)) & (al U G!al)
a & al & (b | c) & (al U G!al) a & al & (b | c) & (al U G!al)
0
al & ((a & b) U (al & !X[!]al)) & (al U G!al)
EOF EOF
checkopt --ltl --from-ltlf='!dead' <<EOF checkopt --ltl --from-ltlf='!dead' <<EOF
@ -324,10 +345,12 @@ checkopt --ltl --from-ltlf='!dead' <<EOF
!dead & (G(dead | F(a & !dead)) | G(b | dead)) & (!dead U Gdead) !dead & (G(dead | F(a & !dead)) | G(b | dead)) & (!dead U Gdead)
!dead & ((b | dead) W G(dead | F(a & !dead))) & (!dead U Gdead) !dead & ((b | dead) W G(dead | F(a & !dead))) & (!dead U Gdead)
!dead & (a U (!dead & F(b & !dead))) & (!dead U Gdead) !dead & (a U (!dead & F(b & !dead))) & (!dead U Gdead)
!dead & G(dead | (a & X(b & !dead))) & (!dead U Gdead) !dead & G(dead | (a & X(b | dead))) & (!dead U Gdead)
!dead & X(a & !dead) & (!dead U Gdead) !dead & X(a | dead) & (!dead U Gdead)
!dead & F(a & !dead & !X(a & !dead) & X(b & !dead)) & (!dead U Gdead) !dead & F(a & !dead & !X(a | dead) & X(b | dead)) & (!dead U Gdead)
a & !dead & (b | c) & (!dead U Gdead) a & !dead & (b | c) & (!dead U Gdead)
0
!dead & ((a & b) U (!dead & !X[!]!dead)) & (!dead U Gdead)
EOF EOF
cat >in <<EOF cat >in <<EOF

View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement # Copyright (C) 2014, 2015, 2019 Laboratoire de Recherche et Développement
# de l'Epita (LRDE). # de l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
@ -52,6 +52,7 @@ p1 U (p4 | (p3 xor (p4 W p0)))
1 U (p4 | (p3 xor (p4 W p0))) 1 U (p4 | (p3 xor (p4 W p0)))
Xp1 U (p4 | !(p4 W p0)) Xp1 U (p4 | !(p4 W p0))
Xp1 W (p4 | (p3 xor (p4 W p0))) Xp1 W (p4 | (p3 xor (p4 W p0)))
X(0) U (p4 | (p3 xor (p4 W p0)))
Xp1 U (p4 | (p3 xor (p4 W 0))) Xp1 U (p4 | (p3 xor (p4 W 0)))
Xp4 U (p4 | (p3 xor (p4 W p0))) Xp4 U (p4 | (p3 xor (p4 W p0)))
Xp3 U (p4 | (p3 xor (p4 W p0))) Xp3 U (p4 | (p3 xor (p4 W p0)))
@ -74,10 +75,10 @@ Xp4 R p3
p3 W !p0 p3 W !p0
Xp4 W !p0 Xp4 W !p0
(p4 R p3) W !p0 (p4 R p3) W !p0
(0 R p3) W !p0
(Xp4 R p3) W p0 (Xp4 R p3) W p0
(Xp4 R p3) W 0 (Xp4 R p3) W 0
(p3 W Xp4) W !p0 (p3 W Xp4) W !p0
(X(0) R p3) W !p0
(Xp3 R p3) W !p0 (Xp3 R p3) W !p0
(Xp0 R p3) W !p0 (Xp0 R p3) W !p0
(Xp4 R p4) W !p0 (Xp4 R p4) W !p0
@ -180,11 +181,11 @@ F!{{p2;p0}[:*]}
{{p2;p0}[:*]}[]-> Xp0 {{p2;p0}[:*]}[]-> Xp0
F({p2;p0}[]-> Xp0) F({p2;p0}[]-> Xp0)
F({{p2;p0}[:*]}[]-> p0) F({{p2;p0}[:*]}[]-> p0)
F({{p2;p0}[:*]}[]-> 0)
F({p0[*2][:*]}[]-> Xp0) F({p0[*2][:*]}[]-> Xp0)
F({p2[*2][:*]}[]-> Xp2) F({p2[*2][:*]}[]-> Xp2)
F({{1;p0}[:*]}[]-> Xp0) F({{1;p0}[:*]}[]-> Xp0)
F({{p2;1}[:*]}[]-> Xp0) F({{p2;1}[:*]}[]-> Xp0)
F({{p2;p0}[:*]}[]-> X(0))
EOF EOF
echo '1,a,3' > input echo '1,a,3' > input

View file

@ -114,17 +114,19 @@ grep -q p2 out
grep p3 out && exit 1 grep p3 out && exit 1
# We should be able to generate exactly two formulas with 0 atomic # We should be able to generate exactly three formulas with 0 atomic
# propositions. # propositions and at most 2 nodes.
run 0 randltl -n2 0 | sort > out run 0 randltl -n3 --tree-size=..2 0 > out
sort <out >out2
cat >expected <<EOF cat >expected <<EOF
0 0
1 1
X(0)
EOF EOF
diff out expected diff out2 expected
# requesting more formulas should fail # requesting more formulas should fail
run 2 randltl -n3 0 run 2 randltl -n4 --tree-size=..2 0
# If more numbers are given, there are interpreted as atomic propositions # If more numbers are given, there are interpreted as atomic propositions
run 0 randltl -n1000 0 1 > out run 0 randltl -n1000 0 1 > out

View file

@ -24,19 +24,24 @@
set -e set -e
cat >ok.in <<EOF cat >ok.in <<\EOF
X[4]a X[4]a
X[3!]a
G[2:4]a G[2:4]a
G[4:2]a G[4:2]a
F[2:4]a F[2:4]a
F[4:2]a F[4:2]a
F[2:$]a F[2:$]a
F[2..]a F[2..]a
F[2:$!]a
F[2:3!]a
X [4]a | b X [4]a | b
G [2:4] a | b G [2:4] a | b
G [4:2] a | b G [4:2] a | b
G [2:] a | b G [2:] a | b
G [2..] a | b G [2..] a | b
G [2..!] a | b
G [2..3!] a | b
F [2:4] a | b F [2:4] a | b
F [4:2]a | F[2:2]b F [4:2]a | F[2:2]b
F[]a|G[]b|X[]c F[]a|G[]b|X[]c
@ -59,19 +64,24 @@ EOF
ltlfilt -F ok.in > ok.out ltlfilt -F ok.in > ok.out
cat >expect <<EOF cat >expect <<\EOF
XXXXa XXXXa
X[!]X[!]X[!]a
XX(a & X(a & Xa)) XX(a & X(a & Xa))
XX(a & X(a & Xa)) XX(a & X(a & Xa))
XX(a | X(a | Xa)) XX(a | X(a | Xa))
XX(a | X(a | Xa)) XX(a | X(a | Xa))
XXFa XXFa
XXFa XXFa
X[!]X[!]Fa
X[!]X[!](a | X[!]a)
b | XXXXa b | XXXXa
b | XX(a & X(a & Xa)) b | XX(a & X(a & Xa))
b | XX(a & X(a & Xa)) b | XX(a & X(a & Xa))
b | XXGa b | XXGa
b | XXGa b | XXGa
b | X[!]X[!]Ga
b | X[!]X[!](a & X[!]a)
b | XX(a | X(a | Xa)) b | XX(a | X(a | Xa))
XX(a | X(a | Xa)) | XXb XX(a | X(a | Xa)) | XXb
FGa | Gb | XGc FGa | Gb | XGc
@ -99,14 +109,19 @@ cat >err.in <<EOF
F[ F[
F[3:1] F[3:1]
F[3:1][2:1] F[3:1][2:1]
F[2]a
F[2!]a
F[a F[a
G[2:4] G[2:4]
G[2:.]a G[2:.]a
G[4]a G[4]a
G[4!]a
G[a G[a
X[2 X[2
X[2] X[2]
X[2:3]
X[2:4]a X[2:4]a
X[2:4!]a
X[a X[a
{a ## b} {a ## b}
{a ##7} {a ##7}
@ -122,6 +137,7 @@ numoreof="$num or end of formula"
sep="separator for square bracket operator" sep="separator for square bracket operator"
undefined='$undefined' undefined='$undefined'
closingbkt='square bracket operator, expecting closing bracket' closingbkt='square bracket operator, expecting closing bracket'
eclosingbkt='expecting closing bracket or closing !]'
ltlfilt -F err.in 2>err && exit 1 ltlfilt -F err.in 2>err && exit 1
cat >expect2 <<EOF cat >expect2 <<EOF
@ -153,6 +169,16 @@ missing right operand for "F[.] operator"
ignoring trailing garbage ignoring trailing garbage
ltlfilt:err.in:4: parse error: ltlfilt:err.in:4: parse error:
>>> F[2]a
^^^^
F[n:m] expects two parameters
ltlfilt:err.in:5: parse error:
>>> F[2!]a
^^^^^
F[n:m!] expects two parameters
ltlfilt:err.in:6: parse error:
>>> F[a >>> F[a
^ ^
syntax error, unexpected $undefined, expecting $numoreof syntax error, unexpected $undefined, expecting $numoreof
@ -161,7 +187,7 @@ syntax error, unexpected $undefined, expecting $numoreof
^^^ ^^^
missing closing bracket for F[.] missing closing bracket for F[.]
ltlfilt:err.in:5: parse error: ltlfilt:err.in:7: parse error:
>>> G[2:4] >>> G[2:4]
^ ^
syntax error, unexpected end of formula syntax error, unexpected end of formula
@ -170,21 +196,26 @@ syntax error, unexpected end of formula
^^^^^^ ^^^^^^
missing right operand for "G[.] operator" missing right operand for "G[.] operator"
ltlfilt:err.in:6: parse error: ltlfilt:err.in:8: parse error:
>>> G[2:.]a >>> G[2:.]a
^ ^
syntax error, unexpected $undefined, expecting closing bracket syntax error, unexpected $undefined, $eclosingbkt
>>> G[2:.]a >>> G[2:.]a
^^^^^^ ^^^^^^
treating this G[.] as a simple G treating this G[.] as a simple G
ltlfilt:err.in:7: parse error: ltlfilt:err.in:9: parse error:
>>> G[4]a >>> G[4]a
^^^^ ^^^^
G[n:m] expects two parameters G[n:m] expects two parameters
ltlfilt:err.in:8: parse error: ltlfilt:err.in:10: parse error:
>>> G[4!]a
^^^^^
G[n:m!] expects two parameters
ltlfilt:err.in:11: parse error:
>>> G[a >>> G[a
^ ^
syntax error, unexpected $undefined, expecting $numoreof syntax error, unexpected $undefined, expecting $numoreof
@ -193,16 +224,16 @@ syntax error, unexpected $undefined, expecting $numoreof
^^^ ^^^
missing closing bracket for G[.] missing closing bracket for G[.]
ltlfilt:err.in:9: parse error: ltlfilt:err.in:12: parse error:
>>> X[2 >>> X[2
^ ^
syntax error, unexpected end of formula, expecting closing bracket syntax error, unexpected end of formula, $eclosingbkt
>>> X[2 >>> X[2
^^^ ^^^
missing closing bracket for X[.] missing closing bracket for X[.]
ltlfilt:err.in:10: parse error: ltlfilt:err.in:13: parse error:
>>> X[2] >>> X[2]
^ ^
syntax error, unexpected end of formula syntax error, unexpected end of formula
@ -211,25 +242,43 @@ syntax error, unexpected end of formula
^^^^ ^^^^
missing right operand for "X[.] operator" missing right operand for "X[.] operator"
ltlfilt:err.in:11: parse error: ltlfilt:err.in:14: parse error:
>>> X[2:3]
^
syntax error, unexpected separator for square bracket operator, $eclosingbkt
>>> X[2:3]
^^^^^^
missing closing bracket for X[.]
ltlfilt:err.in:15: parse error:
>>> X[2:4]a >>> X[2:4]a
^ ^
syntax error, unexpected $sep, expecting closing bracket syntax error, unexpected $sep, $eclosingbkt
>>> X[2:4]a >>> X[2:4]a
^^^^^^^ ^^^^^^^
treating this X[.] as a simple X treating this X[.] as a simple X
ltlfilt:err.in:12: parse error: ltlfilt:err.in:16: parse error:
>>> X[2:4!]a
^
syntax error, unexpected separator for square bracket operator, $eclosingbkt
>>> X[2:4!]a
^^^^^^^^
treating this X[.!] as a simple X[!]
ltlfilt:err.in:17: parse error:
>>> X[a >>> X[a
^ ^
syntax error, unexpected $undefined, expecting $numoreof syntax error, unexpected $undefined, expecting closing !] or $numoreof
>>> X[a >>> X[a
^^^ ^^^
missing closing bracket for X[.] missing closing bracket for X[.]
ltlfilt:err.in:13: parse error: ltlfilt:err.in:18: parse error:
>>> {a ## b} >>> {a ## b}
^ ^
syntax error, unexpected $undefined syntax error, unexpected $undefined
@ -238,7 +287,7 @@ syntax error, unexpected $undefined
^^^^ ^^^^
ignoring this ignoring this
ltlfilt:err.in:14: parse error: ltlfilt:err.in:19: parse error:
>>> {a ##7} >>> {a ##7}
^ ^
syntax error, unexpected closing brace syntax error, unexpected closing brace
@ -247,7 +296,7 @@ syntax error, unexpected closing brace
^^^ ^^^
missing right operand for "SVA delay operator" missing right operand for "SVA delay operator"
ltlfilt:err.in:15: parse error: ltlfilt:err.in:20: parse error:
>>> {a ##[::] b} >>> {a ##[::] b}
^ ^
syntax error, unexpected separator for $closingbkt syntax error, unexpected separator for $closingbkt
@ -256,12 +305,12 @@ syntax error, unexpected separator for $closingbkt
^^^^^^ ^^^^^^
treating this delay block as ##1 treating this delay block as ##1
ltlfilt:err.in:16: parse error: ltlfilt:err.in:21: parse error:
>>> {a ##[2:1] b} >>> {a ##[2:1] b}
^ ^
reversed range reversed range
ltlfilt:err.in:17: parse error: ltlfilt:err.in:22: parse error:
>>> {a ##[1:2]} >>> {a ##[1:2]}
^ ^
syntax error, unexpected closing brace syntax error, unexpected closing brace
@ -270,7 +319,7 @@ syntax error, unexpected closing brace
^^^^^^^ ^^^^^^^
missing right operand for "SVA delay operator" missing right operand for "SVA delay operator"
ltlfilt:err.in:18: parse error: ltlfilt:err.in:23: parse error:
>>> {##[1:2]} >>> {##[1:2]}
^ ^
syntax error, unexpected closing brace syntax error, unexpected closing brace
@ -280,4 +329,4 @@ syntax error, unexpected closing brace
missing right operand for "SVA delay operator" missing right operand for "SVA delay operator"
EOF EOF
diff err expect2 diff -u err expect2

View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2012, 2013, 2015, 2016 Laboratoire de Recherche et # Copyright (C) 2012, 2013, 2015, 2016, 2019 Laboratoire de Recherche et
# Développement de l'Epita (LRDE). # Développement de l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
@ -64,3 +64,9 @@ diff expected output
randltl --psl -8 --seed 0 --tree-size 16 a b c -n 100 > formulae randltl --psl -8 --seed 0 --tree-size 16 a b c -n 100 > formulae
../reduc -f -h 0 formulae ../reduc -f -h 0 formulae
echo 'Ⓧa' >in
ltlfilt -8 -f 'X[!]a' >out
diff in out
ltlfilt -8 -F in >out
diff in out

View file

@ -587,21 +587,14 @@
"X(p2 & X(p2 U (!p0 | !(1 U !p2))))\n", "X(p2 & X(p2 U (!p0 | !(1 U !p2))))\n",
"(1 U p2) | (X(!p2 | !(1 U !p2)) U (1 U (!p1 & (1 U p2))))\n", "(1 U p2) | (X(!p2 | !(1 U !p2)) U (1 U (!p1 & (1 U p2))))\n",
"XX!(1 U !((X!p1 U (!p2 U (!p0 & !p2))) | X!(1 U !p0)))\n", "XX!(1 U !((X!p1 U (!p2 U (!p0 & !p2))) | X!(1 U !p0)))\n",
"XX(1 U (p1 U ((p0 & p1) | !(1 U !p1))))\n", "0\n",
"p2 & Xp0\n" "XX(1 U (p1 U ((p0 & p1) | !(1 U !p1))))\n"
] ]
} }
], ],
"source": [ "source": [
"for formula in spot.randltl(3, 10).simplify().unabbreviate(\"WMGFR\"): print(formula)" "for formula in spot.randltl(3, 10).simplify().unabbreviate(\"WMGFR\"): print(formula)"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {
@ -620,7 +613,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.7.3" "version": "3.7.4+"
} }
}, },
"nbformat": 4, "nbformat": 4,