Commit 58389bdb authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

tl: extend F[n:m] and G[n:m] to the case of m=$

Suggested by Victor Khomenko.

* spot/tl/formula.cc, spot/tl/formula.hh, spot/parsetl/parsetl.yy:
Implement this.
* NEWS, doc/tl/tl.tex: Document it.
* tests/core/sugar.test, tests/python/ltlparse.py: Add some tests.
parent 74786324
Pipeline #9662 passed with stages
in 149 minutes and 52 seconds
...@@ -93,6 +93,9 @@ New in spot 2.7.4.dev (not yet released) ...@@ -93,6 +93,9 @@ New in spot 2.7.4.dev (not yet released)
terms of the existing PSL operators. ##[+] and ##[*] are sugar terms of the existing PSL operators. ##[+] and ##[*] are sugar
for ##[1:$] and ##[0:$]. for ##[1:$] and ##[0:$].
- The F[n:m] and G[n:m] operators introduced in Spot 2.7 now
support the case where m=$.
- spot::relabel_apply() makes it easier to reverse the effect - spot::relabel_apply() makes it easier to reverse the effect
of spot::relabel() or spot::relabel_bse() on formula. of spot::relabel() or spot::relabel_bse() on formula.
......
...@@ -523,7 +523,7 @@ $\M$, and $\W$ if you are only familiar with $\X$ and $\U$. ...@@ -523,7 +523,7 @@ $\M$, and $\W$ if you are only familiar with $\X$ and $\U$.
\subsection{Syntactic Sugar} \subsection{Syntactic Sugar}
The syntax on the left is equivalent to the syntax on the right. The syntax on the left is equivalent to the syntax on the right.
These rewritings taken from the syntax of TSLF~\citep{jacobs.16.synt} Some of rewritings taken from the syntax of TSLF~\citep{jacobs.16.synt}
are performed from left to right when parsing a formula. They express are performed from left to right when parsing a formula. They express
the fact that some formula $f$ has to be true in $n$ steps, or at some the fact that some formula $f$ has to be true in $n$ steps, or at some
or all times between $n$ and $m$ steps. or all times between $n$ and $m$ steps.
...@@ -532,9 +532,11 @@ or all times between $n$ and $m$ steps. ...@@ -532,9 +532,11 @@ or all times between $n$ and $m$ steps.
\XREP{\mvar{n}} f \XREP{\mvar{n}} f
& \equiv \underbrace{\X\X\ldots\X}_{\mathclap{\text{\mvar{n} occurrences of~}\X}} f \\ & \equiv \underbrace{\X\X\ldots\X}_{\mathclap{\text{\mvar{n} occurrences of~}\X}} f \\
\FREP{\mvar{n}:\mvar{m}}f \FREP{\mvar{n}:\mvar{m}}f
& \equiv \underbrace{\vphantom{(}\X\X\ldots\X}_{\mathclap{\text{\mvar{n} occ. of~}\X}} (f \OR \underbrace{\X(f \OR \X(\ldots \OR \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 \OR \underbrace{\X(f \OR \X(\ldots \OR \X f))}_{\mathclap{\mvar{m}-\mvar{n}\text{~occ. of~}\X}})
& \FREP{\mvar{n}:}f &\equiv \XREP{\mvar{n}}\F{}f\\
\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\\
\end{align*} \end{align*}
\subsection{Trivial Identities (Occur Automatically)} \subsection{Trivial Identities (Occur Automatically)}
......
...@@ -887,6 +887,10 @@ subformula: booleanatom ...@@ -887,6 +887,10 @@ subformula: booleanatom
| 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_unbounded OP_SQBKT_CLOSE
subformula %prec OP_FREP
{ $$ = fnode::nested_unop_range(op::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"); }
...@@ -904,6 +908,10 @@ subformula: booleanatom ...@@ -904,6 +908,10 @@ 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_unbounded OP_SQBKT_CLOSE
subformula %prec OP_GREP
{ $$ = fnode::nested_unop_range(op::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,
......
...@@ -1657,11 +1657,14 @@ namespace spot ...@@ -1657,11 +1657,14 @@ namespace spot
const fnode* res = f; const fnode* res = f;
if (max < min) if (max < min)
std::swap(min, max); std::swap(min, max);
for (unsigned i = min; i < max; ++i) if (max != unbounded())
{ for (unsigned i = min; i < max; ++i)
const fnode* a = f->clone(); {
res = fnode::multop(bo, {a, fnode::unop(uo, res)}); const fnode* a = f->clone();
} res = fnode::multop(bo, {a, fnode::unop(uo, res)});
}
else
res = fnode::unop(bo == op::Or ? op::F : op::G, res);
for (unsigned i = 0; i < min; ++i) for (unsigned i = 0; i < min; ++i)
res = fnode::unop(uo, res); res = fnode::unop(uo, res);
return res; return res;
......
...@@ -906,7 +906,8 @@ namespace spot ...@@ -906,7 +906,8 @@ namespace spot
/// \brief Construct F[n:m] /// \brief Construct F[n:m]
/// ///
/// F[2:3] = XX(a | Xa) /// F[2:3]a = XX(a | Xa)
/// F[2:$]a = XXFa
/// ///
/// This syntax is from TSLF; the operator is called next_e![n..m] in PSL. /// This syntax is from TSLF; the operator is called next_e![n..m] in PSL.
static formula F(unsigned min_level, unsigned max_level, const formula& f) static formula F(unsigned min_level, unsigned max_level, const formula& f)
...@@ -916,7 +917,8 @@ namespace spot ...@@ -916,7 +917,8 @@ namespace spot
/// \brief Construct G[n:m] /// \brief Construct G[n:m]
/// ///
/// G[2:3] = XX(a & Xa) /// G[2:3]a = XX(a & Xa)
/// G[2:$]a = XXGa
/// ///
/// This syntax is from TSLF; the operator is called next_a![n..m] in PSL. /// This syntax is from TSLF; the operator is called next_a![n..m] in PSL.
static formula G(unsigned min_level, unsigned max_level, const formula& f) static formula G(unsigned min_level, unsigned max_level, const formula& f)
...@@ -1217,6 +1219,10 @@ namespace spot ...@@ -1217,6 +1219,10 @@ namespace spot
/// ///
/// For instance nested_unup_range(op::X, op::Or, 2, 4, a) returns /// For instance nested_unup_range(op::X, op::Or, 2, 4, a) returns
/// XX(a | X(a | Xa)). /// XX(a | X(a | Xa)).
///
/// For `max==unbounded()`, \a uo is repeated \a min times, and
/// its child is set to `F(a)` if \a bo is `op::Or` or to `G(a)`
/// otherwise.
static const formula nested_unop_range(op uo, op bo, unsigned min, static const formula nested_unop_range(op uo, op bo, unsigned min,
unsigned max, formula f) unsigned max, formula f)
{ {
......
...@@ -30,9 +30,13 @@ G[2:4]a ...@@ -30,9 +30,13 @@ 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
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
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
...@@ -61,9 +65,13 @@ XX(a & X(a & Xa)) ...@@ -61,9 +65,13 @@ 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
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 | 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
...@@ -93,7 +101,7 @@ F[3:1] ...@@ -93,7 +101,7 @@ F[3:1]
F[3:1][2:1] F[3:1][2:1]
F[a F[a
G[2:4] G[2:4]
G[2:]a G[2:.]a
G[4]a G[4]a
G[a G[a
X[2 X[2
...@@ -163,12 +171,12 @@ syntax error, unexpected end of formula ...@@ -163,12 +171,12 @@ 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:6: parse error:
>>> G[2:]a >>> G[2:.]a
^ ^
syntax error, unexpected closing bracket, expecting $num syntax error, unexpected $undefined, expecting closing bracket
>>> 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:7: parse error:
......
# -*- mode: python; coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2009-2012, 2014-2017 Laboratoire de Recherche et # Copyright (C) 2009-2012, 2014-2017, 2019 Laboratoire de Recherche et
# Développement de l'Epita (LRDE). # Développement de l'Epita (LRDE).
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6), # Copyright (C) 2003, 2004 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
...@@ -199,3 +199,14 @@ for (x, msg) in [('a->', "missing right operand for \"implication operator\""), ...@@ -199,3 +199,14 @@ for (x, msg) in [('a->', "missing right operand for \"implication operator\""),
del f9 del f9
assert spot.fnode_instances_check() assert spot.fnode_instances_check()
f = spot.formula_F(2, 4, spot.formula_ap("a"))
assert f == spot.formula("XX(a | X(a | X(a)))")
f = spot.formula_G(2, 4, spot.formula_ap("a"))
assert f == spot.formula("XX(a & X(a & X(a)))")
f = spot.formula_X(2, spot.formula_ap("a"))
assert f == spot.formula("XX(a)")
f = spot.formula_G(2, spot.formula_unbounded(), spot.formula_ap("a"))
assert f == spot.formula("XXG(a)")
f = spot.formula_F(2, spot.formula_unbounded(), spot.formula_ap("a"))
assert f == spot.formula("XXF(a)")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment