{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import display\n",
"import spot\n",
"from spot.jupyter import display_inline\n",
"spot.setup()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To build an automaton from an LTL formula, simply call `translate()` with a formula, and a list of options to characterize the automaton you want (those options have the same name as the long options name of the `ltl2tgba` tool, and they can be abbreviated)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c18e310> >"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = spot.translate('(a U b) & GFc & GFd', 'Buchi', 'state-based', 'complete'); a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The call the `spot.setup()` in the first cells has installed a default style for the graphviz output. If you want to change this style temporarily, you can call the `show(style)` method explicitly. For instance here is a vertical layout with the default font of GraphViz."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.show(\"v\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you want to add some style options to the existing one, pass a dot to the `show()` function in addition to your own style options:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.show(\".st\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `translate()` function can also be called with a formula object. Either as a function, or as a method."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$a \\mathbin{\\mathsf{U}} b$"
],
"text/plain": [
"spot.formula(\"a U b\")"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f = spot.formula('a U b'); f"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c18ef70> >"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.translate(f)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c18f2d0> >"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f.translate()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When used as a method, all the arguments are translation options. Here is a monitor:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c18f3c0> >"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f.translate('mon')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The following three cells show a formulas for which it makes a difference to select `'small'` or `'deterministic'`."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\mathsf{G} a \\lor \\mathsf{G} b \\lor \\mathsf{G} c$"
],
"text/plain": [
"spot.formula(\"Ga | Gb | Gc\")"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f = spot.formula('Ga | Gb | Gc'); f"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f.translate('buchi', 'state-based', 'small').show('.v')"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f.translate('buchi', 'state-based', 'det').show('v.')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here is how to build an unambiguous automaton:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ac1e0> >"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.translate('GFa -> GFb', 'unambig')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Compare with the standard translation:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ac2d0> >"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.translate('GFa -> GFb')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And here is the automaton above with state-based acceptance:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ac720> >"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a = spot.translate('GFa -> GFb', 'sbacc')\n",
"a"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Some example of running the self-loopization algorithm on an automaton:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"a.is_empty()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Reading from file (see `automaton-io.ipynb` for more examples)."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Writing example1.aut\n"
]
}
],
"source": [
"%%file example1.aut\n",
"HOA: v1\n",
"States: 3\n",
"Start: 0\n",
"AP: 2 \"a\" \"b\"\n",
"acc-name: Buchi\n",
"Acceptance: 5 Inf(0)&Fin(1)&Fin(4) | Inf(2)&Inf(3) | Inf(1)\n",
"--BODY--\n",
"State: 0 {3}\n",
"[t] 0\n",
"[0] 1 {1}\n",
"[!0] 2 {0 4}\n",
"State: 1 {3}\n",
"[1] 0\n",
"[0&1] 1 {0}\n",
"[!0&1] 2 {2 4}\n",
"State: 2 \n",
"[!1] 0\n",
"[0&!1] 1 {0}\n",
"[!0&!1] 2 {0 4}\n",
"--END--"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ace70> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ace40> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ac5a0> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c18fc60> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"a = spot.automaton('example1.aut')\n",
"display(a)\n",
"display(spot.remove_fin(a))\n",
"display(a.postprocess('GeneralizedBuchi', 'complete'))\n",
"display(a.postprocess('Buchi', \"SBAcc\"))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"!rm example1.aut"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ad470> >"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.complete(a)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ad2f0> >"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.complete(spot.translate('Ga'))"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.formula('(a W c) & FGa').is_syntactic_persistence()"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"
\n",
"
\n",
"\n",
"\n",
"\n",
"
\n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"
\n",
"
\n",
"\n",
"\n",
"\n",
"
\n",
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Using +1 in the display options is a convenient way to shift the \n",
"# set numbers in the output, as an aid in reading the product.\n",
"a1 = spot.translate('GF(a <-> Xa)')\n",
"a2 = spot.translate('a U b & GFc')\n",
"display_inline(a1.show('.t'), a2.show('.t+1'))\n",
"# the product should display pairs of states, unless asked not to (using '1').\n",
"p = spot.product(a1, a2)\n",
"display_inline(p.show('.t'), p.show('.t1'), per_row=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Explicit determinization after translation:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ae250> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"False"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"a = spot.translate('FGa')\n",
"display(a)\n",
"display(a.is_deterministic())"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1aedf0> >"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.tgba_determinize(a)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Determinization by `translate()`. The `generic` option allows any acceptance condition to be used instead of the default generalized Büchi."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ac570> >"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.translate('FGa', 'generic', 'deterministic')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Translation to state-based co-Büchi automaton"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.translate('FGa', 'coBuchi', 'deterministic', 'sbacc').show('.b')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Translation to parity automaton. Specifying just `parity max odd` requires a parity acceptance. Adding `colored` ensures that each transition (or state if `sbacc` is also given) has a color, as people usually expect in parity automata."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1aec70> >"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.translate('FGa', 'parity max odd', 'colored')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Adding an atomic proposition to all edges"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ae250> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ae250> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import buddy\n",
"display(a)\n",
"b = buddy.bdd_ithvar(a.register_ap('b'))\n",
"for e in a.edges():\n",
" e.cond &= b\n",
"display(a)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Adding an atomic proposition to the edge between 0 and 1:"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/html": [
"\n",
"\n",
"\n",
"\n",
"\n"
],
"text/plain": [
" *' at 0x7f504c1ae250> >"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c = buddy.bdd_ithvar(a.register_ap('c'))\n",
"for e in a.out(0):\n",
" if e.dst == 1:\n",
" e.cond &= c\n",
"a"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.11.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}