* python/spot/impl.i, python/spot/__init__.py: Implement it. * NEWS: Mention it. * tests/python/atva16-fig2a.ipynb, tests/python/atva16-fig2b.ipynb, tests/python/formulas.ipynb, tests/python/ltsmin-dve.ipynb, tests/python/ltsmin-pml.ipynb, tests/python/stutter-inv.ipynb, doc/org/tut02.org: Modernize.
856 lines
27 KiB
Text
856 lines
27 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Handling LTL and PSL formulas\n",
|
|
"============================="
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import spot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"For interactive use, formulas can be entered as text strings and passed to the `spot.formula` constructor."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))$"
|
|
],
|
|
"text/plain": [
|
|
"p1 U (p2 R (p3 & !p4))"
|
|
]
|
|
},
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"f = spot.formula('p1 U p2 R (p3 & !p4)')\n",
|
|
"f"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$\\{a \\mathbin{\\mathsf{;}} b^{\\star} \\mathbin{\\mathsf{;}} c^+\\}\\mathrel{\\Diamond\\kern-1.7pt\\raise.4pt\\hbox{$\\mathord{\\rightarrow}$}} \\mathsf{G} \\mathsf{F} b$"
|
|
],
|
|
"text/plain": [
|
|
"{a;b[*];c[+]}<>-> GFb"
|
|
]
|
|
},
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"g = spot.formula('{a;b*;c[+]}<>->GFb'); g"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"By default the parser recognizes an infix syntax, but when this fails, it tries to read the formula with the [LBT](http://www.tcs.hut.fi/Software/maria/tools/lbt/) syntax:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$c \\land (a \\lor b)$"
|
|
],
|
|
"text/plain": [
|
|
"c & (a | b)"
|
|
]
|
|
},
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"h = spot.formula('& | a b c'); h"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Passing a `formula` to `spot.formula` simply returns the formula."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$c \\land (a \\lor b)$"
|
|
],
|
|
"text/plain": [
|
|
"c & (a | b)"
|
|
]
|
|
},
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.formula(h)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"By default, a formula object is presented using mathjax as above.\n",
|
|
"When a formula is converted to string you get Spot's syntax by default:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"'p1 U (p2 R (p3 & !p4))'"
|
|
]
|
|
},
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"str(f)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"If you prefer to print the string in another syntax, you may use the `to_str()` method, with an argument that indicates the output format to use. The `latex` format assumes that you will the define macros such as `\\U`, `\\R` to render all operators as you wish. On the otherhand, the `sclatex` (with `sc` for self-contained) format hard-codes the rendering of each of those operators: this is typically the output that is used to render formulas using MathJax in a notebook. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"spot p1 U (p2 R (p3 & !p4))\n",
|
|
"spin p1 U (p2 V (p3 && !p4))\n",
|
|
"lbt U p1 V p2 & p3 ! p4\n",
|
|
"wring (p1=1) U ((p2=1) R ((p3=1) * (p4=0)))\n",
|
|
"utf8 p1 U (p2 R (p3∧¬p4))\n",
|
|
"latex p_{1} \\U (p_{2} \\R (p_{3} \\land \\lnot p_{4}))\n",
|
|
"sclatex p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"for i in ['spot', 'spin', 'lbt', 'wring', 'utf8', 'latex', 'sclatex']:\n",
|
|
" print(\"%-10s%s\" % (i, f.to_str(i)))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Formulas output via `format()` can also use some convenient shorthand to select the syntax:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Spin: p1 U (p2 V (p3 && !p4))\n",
|
|
"Spin+parentheses: (p1) U ((p2) V ((p3) && (!(p4))))\n",
|
|
"Spot (default): p1 U (p2 R (p3 & !p4))\n",
|
|
"Spot+shell quotes: 'p1 U (p2 R (p3 & !p4))'\n",
|
|
"LBT, right aligned: ~~~~~~~~~~~~~~~~~~~~~U p1 V p2 & p3 ! p4\n",
|
|
"LBT, no M/W/R: U p1 U & p3 ! p4 | & & p2 p3 ! p4 G & p3 ! p4\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print(\"\"\"\\\n",
|
|
"Spin: {0:s}\n",
|
|
"Spin+parentheses: {0:sp}\n",
|
|
"Spot (default): {0}\n",
|
|
"Spot+shell quotes: {0:q}\n",
|
|
"LBT, right aligned: {0:l:~>40}\n",
|
|
"LBT, no M/W/R: {0:[MWR]l}\"\"\".format(f))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"The specifiers that can be used with `format` are documented as follows:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Help on function __format__ in module spot:\n",
|
|
"\n",
|
|
"__format__(self, spec)\n",
|
|
" Format the formula according to `spec`.\n",
|
|
" \n",
|
|
" Parameters\n",
|
|
" ----------\n",
|
|
" spec : str, optional\n",
|
|
" a list of letters that specify how the formula\n",
|
|
" should be formatted.\n",
|
|
" \n",
|
|
" Supported specifiers\n",
|
|
" --------------------\n",
|
|
" \n",
|
|
" - 'f': use Spot's syntax (default)\n",
|
|
" - '8': use Spot's syntax in UTF-8 mode\n",
|
|
" - 's': use Spin's syntax\n",
|
|
" - 'l': use LBT's syntax\n",
|
|
" - 'w': use Wring's syntax\n",
|
|
" - 'x': use LaTeX output\n",
|
|
" - 'X': use self-contained LaTeX output\n",
|
|
" \n",
|
|
" Add some of those letters for additional options:\n",
|
|
" \n",
|
|
" - 'p': use full parentheses\n",
|
|
" - 'c': escape the formula for CSV output (this will\n",
|
|
" enclose the formula in double quotes, and escape\n",
|
|
" any included double quotes)\n",
|
|
" - 'h': escape the formula for HTML output\n",
|
|
" - 'd': escape double quotes and backslash,\n",
|
|
" for use in C-strings (the outermost double\n",
|
|
" quotes are *not* added)\n",
|
|
" - 'q': quote and escape for shell output, using single\n",
|
|
" quotes or double quotes depending on the contents.\n",
|
|
" - '[...]': rewrite away all the operators specified in brackets,\n",
|
|
" using spot.unabbreviate().\n",
|
|
" \n",
|
|
" - ':spec': pass the remaining specification to the\n",
|
|
" formating function for strings.\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"help(spot.formula.__format__)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"A `spot.formula` object has a number of built-in predicates whose value have been computed when the formula was constructed. For instance you can check whether a formula is in negative normal form using `is_in_nenoform()`, and you can make sure it is an LTL formula (i.e. not a PSL formula) using `is_ltl_formula()`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"True"
|
|
]
|
|
},
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"f.is_in_nenoform() and f.is_ltl_formula()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"False"
|
|
]
|
|
},
|
|
"execution_count": 11,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"g.is_ltl_formula()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Similarly, `is_syntactic_stutter_invariant()` tells wether the structure of the formula guarranties it to be stutter invariant. For LTL formula, this means the `X` operator should not be used. For PSL formula, this function capture all formulas built using the [siPSL grammar](http://www.daxc.de/eth/paper/09atva.pdf)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"True"
|
|
]
|
|
},
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"f.is_syntactic_stutter_invariant()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"False"
|
|
]
|
|
},
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.formula('{a[*];b}<>->c').is_syntactic_stutter_invariant()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"True"
|
|
]
|
|
},
|
|
"execution_count": 14,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.formula('{a[+];b[*]}<>->d').is_syntactic_stutter_invariant()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"`spot.relabel` renames the atomic propositions that occur in a formula, using either letters, or numbered propositions:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$``\\mathit{a > b}\\textrm{''} \\land ``\\mathit{proc[2]@init}\\textrm{''} \\land \\mathsf{G} \\mathsf{F} \\mathit{\\_foo\\_}$"
|
|
],
|
|
"text/plain": [
|
|
"\"a > b\" & \"proc[2]@init\" & GF_foo_"
|
|
]
|
|
},
|
|
"execution_count": 15,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"gf = spot.formula('(GF_foo_) && \"a > b\" && \"proc[2]@init\"'); gf"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$a \\land b \\land \\mathsf{G} \\mathsf{F} c$"
|
|
],
|
|
"text/plain": [
|
|
"a & b & GFc"
|
|
]
|
|
},
|
|
"execution_count": 16,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.relabel(gf, spot.Abc)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$p_{0} \\land p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2}$"
|
|
],
|
|
"text/plain": [
|
|
"p0 & p1 & GFp2"
|
|
]
|
|
},
|
|
"execution_count": 17,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.relabel(gf, spot.Pnn)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"The AST of any formula can be displayed with `show_ast()`. Despite the name, this is not a tree but a DAG, because identical subtrees are merged. Binary operators have their left and right operands denoted with `L` and `R`, while non-commutative n-ary operators have their operands numbered."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"{a;b[*];c[+]}<>-> GFb\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/svg+xml": [
|
|
"<svg height=\"260pt\" viewBox=\"0.00 0.00 269.00 260.00\" width=\"269pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
|
"<g class=\"graph\" id=\"graph0\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
|
|
"<title>G</title>\n",
|
|
"<polygon fill=\"white\" points=\"-4,4 -4,-256 265,-256 265,4 -4,4\" stroke=\"none\"/>\n",
|
|
"<!-- 0 -->\n",
|
|
"<g class=\"node\" id=\"node1\"><title>0</title>\n",
|
|
"<ellipse cx=\"106\" cy=\"-234\" fill=\"none\" rx=\"40.8928\" ry=\"18\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"106\" y=\"-230.3\">EConcat</text>\n",
|
|
"</g>\n",
|
|
"<!-- 1 -->\n",
|
|
"<g class=\"node\" id=\"node2\"><title>1</title>\n",
|
|
"<ellipse cx=\"155\" cy=\"-162\" fill=\"none\" rx=\"35.9954\" ry=\"18\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"155\" y=\"-158.3\">Concat</text>\n",
|
|
"</g>\n",
|
|
"<!-- 0->1 -->\n",
|
|
"<g class=\"edge\" id=\"edge6\"><title>0->1</title>\n",
|
|
"<path d=\"M117.612,-216.411C123.593,-207.868 131.005,-197.278 137.649,-187.787\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"140.604,-189.669 143.471,-179.47 134.869,-185.655 140.604,-189.669\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"113.112\" y=\"-205.211\">L</text>\n",
|
|
"</g>\n",
|
|
"<!-- 7 -->\n",
|
|
"<g class=\"node\" id=\"node8\"><title>7</title>\n",
|
|
"<ellipse cx=\"58\" cy=\"-162\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"58\" y=\"-158.3\">G</text>\n",
|
|
"</g>\n",
|
|
"<!-- 0->7 -->\n",
|
|
"<g class=\"edge\" id=\"edge9\"><title>0->7</title>\n",
|
|
"<path d=\"M94.6247,-216.411C88.6815,-207.744 81.2945,-196.971 74.7146,-187.375\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"77.5052,-185.256 68.9633,-178.988 71.732,-189.215 77.5052,-185.256\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"89.6247\" y=\"-205.211\">R</text>\n",
|
|
"</g>\n",
|
|
"<!-- 2 -->\n",
|
|
"<g class=\"node\" id=\"node3\"><title>2</title>\n",
|
|
"<polygon fill=\"none\" points=\"261,-36 207,-36 207,-0 261,-0 261,-36\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"234\" y=\"-14.3\">a</text>\n",
|
|
"</g>\n",
|
|
"<!-- 1->2 -->\n",
|
|
"<g class=\"edge\" id=\"edge1\"><title>1->2</title>\n",
|
|
"<path d=\"M173.171,-146.485C184.356,-136.683 198.19,-122.858 207,-108 218.359,-88.8432 225.316,-64.4933 229.316,-46.1073\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"232.797,-46.5497 231.341,-36.0554 225.935,-45.1672 232.797,-46.5497\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"169.671\" y=\"-135.285\">1</text>\n",
|
|
"</g>\n",
|
|
"<!-- 3 -->\n",
|
|
"<g class=\"node\" id=\"node4\"><title>3</title>\n",
|
|
"<ellipse cx=\"99\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"99\" y=\"-86.3\">Star</text>\n",
|
|
"</g>\n",
|
|
"<!-- 1->3 -->\n",
|
|
"<g class=\"edge\" id=\"edge3\"><title>1->3</title>\n",
|
|
"<path d=\"M142.293,-145.116C135.032,-136.04 125.792,-124.49 117.715,-114.393\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"120.252,-111.962 111.272,-106.34 114.786,-116.335 120.252,-111.962\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"138.793\" y=\"-133.916\">2</text>\n",
|
|
"</g>\n",
|
|
"<!-- 5 -->\n",
|
|
"<g class=\"node\" id=\"node6\"><title>5</title>\n",
|
|
"<ellipse cx=\"171\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"171\" y=\"-86.3\">Star</text>\n",
|
|
"</g>\n",
|
|
"<!-- 1->5 -->\n",
|
|
"<g class=\"edge\" id=\"edge5\"><title>1->5</title>\n",
|
|
"<path d=\"M158.873,-144.055C160.655,-136.261 162.812,-126.822 164.811,-118.079\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"168.235,-118.804 167.051,-108.275 161.411,-117.244 168.235,-118.804\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"155.373\" y=\"-132.855\">3</text>\n",
|
|
"</g>\n",
|
|
"<!-- 4 -->\n",
|
|
"<g class=\"node\" id=\"node5\"><title>4</title>\n",
|
|
"<polygon fill=\"none\" points=\"81,-36 27,-36 27,-0 81,-0 81,-36\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"54\" y=\"-14.3\">b</text>\n",
|
|
"</g>\n",
|
|
"<!-- 3->4 -->\n",
|
|
"<g class=\"edge\" id=\"edge2\"><title>3->4</title>\n",
|
|
"<path d=\"M88.7888,-73.1159C83.4437,-64.8013 76.7639,-54.4105 70.6903,-44.9627\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"73.4681,-42.8113 65.1164,-36.2921 67.5799,-46.5966 73.4681,-42.8113\" stroke=\"black\"/>\n",
|
|
"</g>\n",
|
|
"<!-- 6 -->\n",
|
|
"<g class=\"node\" id=\"node7\"><title>6</title>\n",
|
|
"<polygon fill=\"none\" points=\"189,-36 135,-36 135,-0 189,-0 189,-36\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"162\" y=\"-14.3\">c</text>\n",
|
|
"</g>\n",
|
|
"<!-- 5->6 -->\n",
|
|
"<g class=\"edge\" id=\"edge4\"><title>5->6</title>\n",
|
|
"<path d=\"M168.821,-72.055C167.83,-64.3456 166.632,-55.0269 165.518,-46.3642\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"168.968,-45.7473 164.221,-36.2753 162.025,-46.64 168.968,-45.7473\" stroke=\"black\"/>\n",
|
|
"</g>\n",
|
|
"<!-- 8 -->\n",
|
|
"<g class=\"node\" id=\"node9\"><title>8</title>\n",
|
|
"<ellipse cx=\"27\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
|
|
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"27\" y=\"-86.3\">F</text>\n",
|
|
"</g>\n",
|
|
"<!-- 7->8 -->\n",
|
|
"<g class=\"edge\" id=\"edge8\"><title>7->8</title>\n",
|
|
"<path d=\"M50.6534,-144.411C46.9858,-136.129 42.4667,-125.925 38.3646,-116.662\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"41.5434,-115.196 34.2938,-107.47 35.1429,-118.031 41.5434,-115.196\" stroke=\"black\"/>\n",
|
|
"</g>\n",
|
|
"<!-- 8->4 -->\n",
|
|
"<g class=\"edge\" id=\"edge7\"><title>8->4</title>\n",
|
|
"<path d=\"M33.3986,-72.411C36.4351,-64.5386 40.1417,-54.9289 43.5695,-46.0421\" fill=\"none\" stroke=\"black\"/>\n",
|
|
"<polygon fill=\"black\" points=\"46.9373,-47.0364 47.2705,-36.4468 40.4062,-44.5172 46.9373,-47.0364\" stroke=\"black\"/>\n",
|
|
"</g>\n",
|
|
"</g>\n",
|
|
"</svg>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.SVG object>"
|
|
]
|
|
},
|
|
"execution_count": 18,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"print(g); g.show_ast()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Any formula can also be classified in the temporal hierarchy of Manna & Pnueli"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/svg+xml": [
|
|
"<svg height=\"210\" version=\"1.1\" width=\"220\" xmlns=\"http://www.w3.org/2000/svg\">\n",
|
|
"<polygon fill=\"cyan\" opacity=\".2\" points=\"20,0 200,120 200,210 20,210\"/>\n",
|
|
"<polygon fill=\"cyan\" opacity=\".2\" points=\"20,120 155,210 20,210\"/>\n",
|
|
"<polygon fill=\"magenta\" opacity=\".15\" points=\"200,0 20,120 20,210 200,210\"/>\n",
|
|
"<polygon fill=\"magenta\" opacity=\".15\" points=\"200,120 65,210 200,210\"/>\n",
|
|
"<g transform=\"translate(40,80)\">\n",
|
|
" <line stroke=\"red\" stroke-width=\"5\" x1=\"-10\" x2=\"10\" y1=\"-10\" y2=\"10\"/>\n",
|
|
" <line stroke=\"red\" stroke-width=\"5\" x1=\"-10\" x2=\"10\" y1=\"10\" y2=\"-10\"/>\n",
|
|
" </g>\n",
|
|
"<g font-size=\"14\" text-anchor=\"middle\">\n",
|
|
"<text x=\"110\" y=\"20\">Reactivity</text>\n",
|
|
"<text x=\"60\" y=\"65\">Recurrence</text>\n",
|
|
"<text x=\"160\" y=\"65\">Persistence</text>\n",
|
|
"<text x=\"110\" y=\"125\">Obligation</text>\n",
|
|
"<text x=\"60\" y=\"185\">Safety</text>\n",
|
|
"<text x=\"160\" y=\"185\">Guarantee</text>\n",
|
|
"</g>\n",
|
|
"<g font-size=\"14\">\n",
|
|
"<text fill=\"gray\" text-anchor=\"begin\" transform=\"rotate(-90,18,210)\" x=\"18\" y=\"210\">Monitor</text>\n",
|
|
"<text fill=\"gray\" text-anchor=\"end\" transform=\"rotate(-90,18,0)\" x=\"18\" y=\"0\">Deterministic Büchi</text>\n",
|
|
"<text fill=\"gray\" text-anchor=\"begin\" transform=\"rotate(-90,214,210)\" x=\"214\" y=\"210\">Terminal Büchi</text>\n",
|
|
"<text fill=\"gray\" text-anchor=\"end\" transform=\"rotate(-90,214,0)\" x=\"214\" y=\"0\">Weak Büchi</text>\n",
|
|
"</g>\n",
|
|
"</svg>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.SVG object>"
|
|
]
|
|
},
|
|
"execution_count": 19,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"g.show_mp_hierarchy()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"'recurrence'"
|
|
]
|
|
},
|
|
"execution_count": 20,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.mp_class(g, 'v')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$\\mathsf{F} (a \\land \\mathsf{X} (\\lnot a \\land b))$"
|
|
],
|
|
"text/plain": [
|
|
"F(a & X(!a & b))"
|
|
]
|
|
},
|
|
"execution_count": 21,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"f = spot.formula('F(a & X(!a & b))'); f"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Etessami's rule for removing X (valid only in stutter-invariant formulas)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$\\mathsf{F} (a \\land ((a \\land (a \\mathbin{\\mathsf{U}} (\\lnot a \\land b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} \\lnot a) \\lor (b \\mathbin{\\mathsf{U}} \\lnot a))) \\lor (\\lnot a \\land (\\lnot a \\mathbin{\\mathsf{U}} (a \\land \\lnot a \\land b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} a) \\lor (b \\mathbin{\\mathsf{U}} a))) \\lor (b \\land (b \\mathbin{\\mathsf{U}} (\\lnot a \\land b \\land \\lnot b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} \\lnot b) \\lor (a \\mathbin{\\mathsf{U}} \\lnot b))) \\lor (\\lnot b \\land (\\lnot b \\mathbin{\\mathsf{U}} (\\lnot a \\land b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} b) \\lor (a \\mathbin{\\mathsf{U}} b))) \\lor (\\lnot a \\land b \\land (\\mathsf{G} \\lnot a \\lor \\mathsf{G} a) \\land (\\mathsf{G} \\lnot b \\lor \\mathsf{G} b))))$"
|
|
],
|
|
"text/plain": [
|
|
"F(a & ((a & (a U (!a & b)) & ((!b U !a) | (b U !a))) | (!a & (!a U (a & !a & b)) & ((!b U a) | (b U a))) | (b & (b U (!a & b & !b)) & ((!a U !b) | (a U !b))) | (!b & (!b U (!a & b)) & ((!a U b) | (a U b))) | (!a & b & (G!a | Ga) & (G!b | Gb))))"
|
|
]
|
|
},
|
|
"execution_count": 22,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.remove_x(f)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Removing abbreviated operators"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$(\\bot \\mathbin{\\mathsf{R}} \\lnot (a \\leftrightarrow b)) \\rightarrow (\\top \\mathbin{\\mathsf{U}} (a \\leftrightarrow b))$"
|
|
],
|
|
"text/plain": [
|
|
"(0 R !(a <-> b)) -> (1 U (a <-> b))"
|
|
]
|
|
},
|
|
"execution_count": 23,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"f = spot.formula(\"G(a xor b) -> F(a <-> b)\")\n",
|
|
"spot.unabbreviate(f, \"GF^\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 24,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/latex": [
|
|
"$(\\top \\mathbin{\\mathsf{U}} ((a \\land b) \\lor (\\lnot a \\land \\lnot b))) \\lor \\lnot (\\bot \\mathbin{\\mathsf{R}} ((\\lnot a \\land b) \\lor (a \\land \\lnot b)))$"
|
|
],
|
|
"text/plain": [
|
|
"(1 U ((a & b) | (!a & !b))) | !(0 R ((!a & b) | (a & !b)))"
|
|
]
|
|
},
|
|
"execution_count": 24,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"spot.unabbreviate(f, \"GF^ei\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Nesting level of operators"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 25,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"U 3\n",
|
|
"F 2\n",
|
|
"U 3\n",
|
|
"F 2\n",
|
|
"FU 4\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"f = spot.formula('F(b & X(a U b U ((a W Fb) | (c U d))))')\n",
|
|
"print(\"U\", spot.nesting_depth(f, spot.op_U))\n",
|
|
"print(\"F\", spot.nesting_depth(f, spot.op_F))\n",
|
|
"# These following two are syntactic sugar for the above two\n",
|
|
"print(\"U\", spot.nesting_depth(f, \"U\"))\n",
|
|
"print(\"F\", spot.nesting_depth(f, \"F\"))\n",
|
|
"# If you want to consider \"U\" and \"F\" are a similar type of\n",
|
|
"# operator, you can count both with\n",
|
|
"print(\"FU\", spot.nesting_depth(f, \"FU\"))"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.6.5"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|