diff --git a/NEWS b/NEWS
index 9b9cfd9f8..8e570c30f 100644
--- a/NEWS
+++ b/NEWS
@@ -234,6 +234,8 @@ New in spot 2.4.4.dev (net yet released)
signal per atomic proposition. For some examples, see the use of
the show() method in https://spot.lrde.epita.fr/ipynb/word.html
+ - The test suite is now using v4 of the Jupyter Notebook format.
+
Deprecation notices:
(These functions still work but compilers emit warnings.)
diff --git a/tests/python/_altscc.ipynb b/tests/python/_altscc.ipynb
index 6c67c1445..92a62c6b0 100644
--- a/tests/python/_altscc.ipynb
+++ b/tests/python/_altscc.ipynb
@@ -1,4 +1,1023 @@
{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "These examples are tests for scc_info on alternating automata."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "from IPython.display import display\n",
+ "import spot\n",
+ "spot.setup(show_default='.bas')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e84e9810> >"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 0&1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "acc-name: Buchi\n",
+ "Acceptance: 1 Inf(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 0\n",
+ "[!0] 1\n",
+ "State: 1\n",
+ "[1] 1 {0}\n",
+ "--END--\n",
+ "''')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "universal edges are handled as if they were many distinct existencial edges from the point of view of `scc_info`, so the acceptance / rejection status is not always meaningful."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e8571900> >"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 0&1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 0&1 {0}\n",
+ "State: 1\n",
+ "[1] 1\n",
+ "--END--\n",
+ "''')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e85070f0> >"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 0&1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 0 {0}\n",
+ "[!0] 1\n",
+ "State: 1\n",
+ "[1] 1&0\n",
+ "--END--\n",
+ "''')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e8507120> >"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 0\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 0\n",
+ "[!0] 1 {0}\n",
+ "State: 1\n",
+ "[1] 1&0\n",
+ "--END--\n",
+ "''')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e8507150> >"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 0\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 0 {0}\n",
+ "[!0] 1 \n",
+ "State: 1\n",
+ "[1] 1&0 {0}\n",
+ "--END--\n",
+ "''')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A corner case for the dot printer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e8507630> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e84e98a0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f41e9624660> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for a in spot.automata('''\n",
+ "HOA: v1\n",
+ "States: 3\n",
+ "Start: 0\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 1&2\n",
+ "State: 1\n",
+ "[1] 1&2 {0}\n",
+ "State: 2\n",
+ "[1] 2\n",
+ "--END--\n",
+ "HOA: v1\n",
+ "States: 3\n",
+ "Start: 0\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 1&2\n",
+ "State: 1\n",
+ "[1] 1 {0}\n",
+ "State: 2\n",
+ "[1] 2\n",
+ "--END--\n",
+ "'''):\n",
+ " display(a)\n",
+ "\n",
+ "a = spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 3\n",
+ "Start: 0&2\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Fin(0)\n",
+ "spot.highlight.edges: 2 2\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 1&2\n",
+ "State: 1\n",
+ "[1] 1&2 {0}\n",
+ "State: 2\n",
+ "[1] 1&2\n",
+ "--END--\n",
+ "''')\n",
+ "display(a, a.show('.basy'))"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,1016 +1035,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "These examples are tests for scc_info on alternating automata."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "from IPython.display import display\n",
- "import spot\n",
- "spot.setup(show_default='.bas')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('''\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 0&1\n",
- "AP: 2 \"a\" \"b\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 1 Inf(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 0\n",
- "[!0] 1\n",
- "State: 1\n",
- "[1] 1 {0}\n",
- "--END--\n",
- "''')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e84e9810> >"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "universal edges are handled as if they were many distinct existencial edges from the point of view of `scc_info`, so the acceptance / rejection status is not always meaningful."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('''\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 0&1\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 0&1 {0}\n",
- "State: 1\n",
- "[1] 1\n",
- "--END--\n",
- "''')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e8571900> >"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('''\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 0&1\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 0 {0}\n",
- "[!0] 1\n",
- "State: 1\n",
- "[1] 1&0\n",
- "--END--\n",
- "''')"
- ],
- "language": "python",
- "metadata": {
- "scrolled": true
- },
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e85070f0> >"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('''\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 0\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 0\n",
- "[!0] 1 {0}\n",
- "State: 1\n",
- "[1] 1&0\n",
- "--END--\n",
- "''')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e8507120> >"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('''\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 0\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 0 {0}\n",
- "[!0] 1 \n",
- "State: 1\n",
- "[1] 1&0 {0}\n",
- "--END--\n",
- "''')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e8507150> >"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A corner case for the dot printer"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for a in spot.automata('''\n",
- "HOA: v1\n",
- "States: 3\n",
- "Start: 0\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 1&2\n",
- "State: 1\n",
- "[1] 1&2 {0}\n",
- "State: 2\n",
- "[1] 2\n",
- "--END--\n",
- "HOA: v1\n",
- "States: 3\n",
- "Start: 0\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 1&2\n",
- "State: 1\n",
- "[1] 1 {0}\n",
- "State: 2\n",
- "[1] 2\n",
- "--END--\n",
- "'''):\n",
- " display(a)\n",
- "\n",
- "a = spot.automaton('''\n",
- "HOA: v1\n",
- "States: 3\n",
- "Start: 0&2\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Fin(0)\n",
- "spot.highlight.edges: 2 2\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 1&2\n",
- "State: 1\n",
- "[1] 1&2 {0}\n",
- "State: 2\n",
- "[1] 1&2\n",
- "--END--\n",
- "''')\n",
- "display(a, a.show('.basy'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e8507630> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e84e98a0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f41e9624660> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 7
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/_aux.ipynb b/tests/python/_aux.ipynb
index ed3527d71..c90d7995c 100644
--- a/tests/python/_aux.ipynb
+++ b/tests/python/_aux.ipynb
@@ -1,73 +1,72 @@
{
- "metadata": {
- "name": "",
- "signature": "sha256:6be10f711b59f226415bc570a040611b0a8c554e61bf92877b8af4040963e0ac"
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
+ "cells": [
{
- "cells": [
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import spot.aux"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Make sure `str_to_svg` reports errors from dot."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
{
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "import spot.aux"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Make sure `str_to_svg` reports errors from dot."
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Calling 'dot' for the conversion to SVG produced the message:\n",
+ "Error: : syntax error in line 1 near 'syntax'\n",
+ "\n"
]
},
{
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.aux.str_to_svg(b'syntax error')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stderr",
- "text": [
- "Calling 'dot' for the conversion to SVG produced the message:\n",
- "Error: : syntax error in line 1 near 'syntax'\n",
- "\n"
- ]
- },
- {
- "ename": "CalledProcessError",
- "evalue": "Command 'dot' returned non-zero exit status 1",
- "output_type": "pyerr",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maux\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstr_to_svg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mb'syntax error'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;32m/home/adl/git/spot/python/spot/aux.py\u001b[0m in \u001b[0;36mstr_to_svg\u001b[0;34m(str)\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0mret\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 61\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 62\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'dot'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 63\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mstdout\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'utf-8'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mCalledProcessError\u001b[0m: Command 'dot' returned non-zero exit status 1"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [],
- "language": "python",
- "metadata": {},
- "outputs": []
+ "ename": "CalledProcessError",
+ "evalue": "Command 'dot' returned non-zero exit status 1.",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0maux\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstr_to_svg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mb'syntax error'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m/home/adl/git/spot/python/spot/aux.py\u001b[0m in \u001b[0;36mstr_to_svg\u001b[0;34m(str)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0mret\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'dot'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 65\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mstdout\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'utf-8'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 66\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mCalledProcessError\u001b[0m: Command 'dot' returned non-zero exit status 1."
+ ]
}
],
- "metadata": {}
+ "source": [
+ "spot.aux.str_to_svg(b'syntax error')"
+ ]
}
- ]
-}
\ No newline at end of file
+ ],
+ "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.4"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tests/python/acc_cond.ipynb b/tests/python/acc_cond.ipynb
index bcff265be..070318900 100644
--- a/tests/python/acc_cond.ipynb
+++ b/tests/python/acc_cond.ipynb
@@ -1,4 +1,1497 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "spot.setup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Acceptance conditions\n",
+ "\n",
+ "The acceptance condition of an automaton specifies which of its paths are accepting.\n",
+ "\n",
+ "The way acceptance conditions are stored in Spot is derived from the way acceptance conditions are specified in the [HOA format](http://adl.github.io/hoaf/). In HOA, acceptance conditions are given as a line of the form:\n",
+ "\n",
+ " Acceptance: 3 (Inf(0)&Fin(1))|Inf(2)\n",
+ "\n",
+ "The number `3` gives the number of acceptance sets used (numbered from `0` to `2` in that case), while the rest of the line is a positive Boolean formula over terms of the form:\n",
+ "- `Inf(n)`, that is true if and only if the set `n` is seen infinitely often,\n",
+ "- `Fin(n)`, that is true if and only if the set `n` should be seen finitely often,\n",
+ "- `t`, always true,\n",
+ "- `f`, always false.\n",
+ "\n",
+ "The HOA specifications additionally allows terms of the form `Inf(!n)` or `Fin(!n)` but Spot automatically rewrites those away when reading an HOA file.\n",
+ "\n",
+ "Note that the number of sets given can be larger than what is actually needed by the acceptance formula.\n",
+ "\n",
+ "Transitions in automata can be tagged as being part of some member sets, and a path in the automaton is accepting if the set of acceptance sets visited along this path satify the acceptance condition.\n",
+ "\n",
+ "Definining acceptance conditions in Spot involves three different types of C++ objects:\n",
+ "\n",
+ "- `spot::acc_cond` is used to represent an acceptance condition, that is: a number of sets and a formula.\n",
+ "- `spot::acc_cond::acc_code`, is used to represent Boolean formula for the acceptance condition using a kind of byte code (hence the name)\n",
+ "- `spot::acc_cond::mark_t`, is a type of bit-vector used to represent membership to acceptance sets.\n",
+ "\n",
+ "In because Swig's support for nested class is limited, these types are available respectively as `spot.acc_cond`, `spot.acc_code`, and `spot.mark_t` in Python.\n",
+ "\n",
+ "## `mark_t`\n",
+ "\n",
+ "Let's start with the simpler of these three objects. `mark_t` is a type of bit vector. Its main constructor takes a sequence of set numbers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{}"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.mark_t()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{0,2,3}"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.mark_t([0, 2, 3])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{0,2,3}"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.mark_t((0, 2, 3))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As seen above, the sequence of set numbers can be specified using a list or a tuple. While from the Python language point of view, using a tuple is faster than using a list, the overhead to converting all the arguments from Python to C++ and then converting the resuslting back from C++ to Python makes this difference completely negligeable. In the following, we opted to use lists, because brackets are more readable than nested parentheses."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{0,2,3,4}\n",
+ "{0}\n",
+ "{2,3}\n"
+ ]
+ }
+ ],
+ "source": [
+ "x = spot.mark_t([0, 2, 3])\n",
+ "y = spot.mark_t([0, 4])\n",
+ "print(x | y)\n",
+ "print(x & y)\n",
+ "print(x - y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The bits can be set, cleared, and tested using the `set()`, `clear()`, and `has()` methods:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{0,2,3,5}\n"
+ ]
+ }
+ ],
+ "source": [
+ "x.set(5)\n",
+ "print(x)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{0,2,5}\n"
+ ]
+ }
+ ],
+ "source": [
+ "x.clear(3)\n",
+ "print(x)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "True\n",
+ "False\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(x.has(2))\n",
+ "print(x.has(3))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Left-shifting will increment all set numbers.\n",
+ "This operation is useful when building the product of two automata: all the set number of one automaton have to be shift by the number of sets used in the other automaton."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{2,4,7}"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x << 2"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Internally, the `mark_t` stores the bit-vector as an integer. This also implies that we currently do not support more than 32 acceptance sets. The underlaying integer can be retrieved using `.id`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{0,2,5}\n",
+ "37\n",
+ "0b100101\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(x)\n",
+ "print(x.id)\n",
+ "print(bin(x.id))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`mark_t` can also be initialized using an integer: in that case the integer is interpreted as a bit vector.\n",
+ "\n",
+ "A frequent error is to use `mark_t(n)` when we really mean `mark_t([n])` or `mark_t((n,))`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{5}\n",
+ "{0,2}\n",
+ "{0,2,4}\n"
+ ]
+ }
+ ],
+ "source": [
+ "# compare\n",
+ "print(spot.mark_t([5]))\n",
+ "# with\n",
+ "print(spot.mark_t(5))\n",
+ "print(spot.mark_t(0b10101))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The different sets can be iterated over with the `sets()` method, that returns a tuble with the index of all bits set."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{0,2,5}\n",
+ "[0, 2, 5]\n",
+ "0\n",
+ "2\n",
+ "5\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(x)\n",
+ "print(list(x.sets()))\n",
+ "for s in x.sets():\n",
+ " print(s)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`count()` return the number of sets in a `mark_t`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "x.count()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`lowest()` returns a `mark_t` containing only the lowest set number. This provides another way to iterate overs all set numbers in cases where you need the result as a `mark_t`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{1}"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.mark_t([1,3,5]).lowest()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{1}\n",
+ "{3}\n",
+ "{5}\n"
+ ]
+ }
+ ],
+ "source": [
+ "v = spot.mark_t([1, 3, 5])\n",
+ "while v: # this stops once v is empty\n",
+ " b = v.lowest()\n",
+ " v -= b\n",
+ " print(b)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`max_set()` returns the number of the highest set plus one. This is usually used to figure out how many sets we need to declare on the `Acceptance:` line of the HOA format:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "6"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.mark_t([1, 3, 5]).max_set()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## `acc_code`\n",
+ "\n",
+ "`acc_code` encodes the formula of the acceptance condition using a kind of bytecode that basically corresponds to an encoding in [reverse Polish notation](http://en.wikipedia.org/wiki/Reverse_Polish_notation) in which conjunctions of `Inf(n)` terms, and disjunctions of `Fin(n)` terms are grouped. In particular, the frequently-used genaralized-Büchi acceptance conditions (like `Inf(0)&Inf(1)&Inf(2)`) are always encoded as a single term (like `Inf({0,1,2})`).\n",
+ "\n",
+ "The simplest way to construct an `acc_code` by passing a string that represent the formula to build."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Inf(0) & Fin(1)) | Inf(2)"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code('(Inf(0)&Fin(1))|Inf(2)')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "You may also use a named acceptance condition:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code('Rabin 2')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The recognized names are the valide values for `acc-name:` in the [HOA format](http://adl.github.io/hoaf/). Additionally numbers may be replaced by ranges of the form `n..m`, in which case a random number is selected in that range."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(Fin(0) | Inf(1)) & (Fin(2) | Inf(3)) & (Fin(4) | Inf(5)) & (Fin(6) | Inf(7))\n",
+ "(Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(spot.acc_code('Streett 2..4'))\n",
+ "print(spot.acc_code('Streett 2..4'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "It may also be convenient to generate a random acceptance condition:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Fin(3) | Inf(1)) & Inf(4) & (Fin(0)|Fin(2))"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code('random 3..5')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `to_cnf()` and `to_dnf()` functions can be used to rewrite the formula into Conjunctive or Disjunctive normal forms. This functions will simplify the resulting formulas to make them irredundant."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | Fin(4))))"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = spot.acc_code('parity min odd 5')\n",
+ "a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Fin(0) & (Inf(1) | Fin(2)) & (Inf(1) | Inf(3) | Fin(4))"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.to_cnf()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Fin(0) & Inf(1)) | (Fin(0) & Fin(2) & Inf(3)) | (Fin(0) & Fin(2) & Fin(4))"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.to_dnf()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The manipulation of `acc_code` objects is quite rudimentary at the moment: it easy to build, but it's harder take appart. In fact we won't attempt to disassemble an `acc_code` object in Python: those things are better done in C++\n",
+ "\n",
+ "Operators `|`, `|=`, `&`, `&=`, `<<`, and `<<=` can be used with their obvious semantics.\n",
+ "Whenever possible, the inplace versions (`|=`, `&=`, `<<=`) should be prefered, because they create less temporary acceptance conditions."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
+ "(Fin(4) & Inf(5)) | (Fin(6) & Inf(7))\n"
+ ]
+ }
+ ],
+ "source": [
+ "x = spot.acc_code('Rabin 2')\n",
+ "y = spot.acc_code('Rabin 2') << 4\n",
+ "print(x)\n",
+ "print(y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(Fin(4) & Inf(5)) | (Fin(6) & Inf(7)) | (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
+ "((Fin(4) & Inf(5)) | (Fin(6) & Inf(7))) & ((Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(x | y)\n",
+ "print(x & y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `complement()` method returns the complemented acceptance condition:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
+ "(Inf(0) | Fin(1)) & (Inf(2) | Fin(3))\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(x)\n",
+ "print(x.complement())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Instead of using `acc_code('string')`, it is also possible to build an acceptance formula from atoms like `Inf({...})`, `Fin({...})`, `t`, or `f`.\n",
+ "\n",
+ "Remember that in our encoding for the formula, terms like `Inf(1)&Inf(2)` and `Fin(3)|Fin(4)|Fin(5)` are actually stored as `Inf({1,2})` and `Fin({3,4,5})`, where `{1,2}` and `{3,4,5}` are instance of `mark_t`. These terms can be generated with the\n",
+ "functions `spot.acc_code.inf(mark)` and `spot.acc_code.fin(mark)`.\n",
+ "\n",
+ "`Inf({})` is equivalent to `t`, and `Fin({})` is equivalent to `f`, but it's better to use the functions `spot.acc_code.t()` or `spot.acc_code.f()` directly."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Fin(3)|Fin(4)|Fin(5)) & (Inf(1)&Inf(2))"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code.inf([1,2]) & spot.acc_code.fin([3,4,5])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "t"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code.inf([])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "t"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code.t()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "f"
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code.fin([])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "f"
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.acc_code.f()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To evaluate an acceptance condition formula on a run, build a `mark_t` containing all the acceptance sets that are seen infinitely often along this run, and call the `accepting()` method."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 32,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "acc = (Fin(0) & Inf(1)) | Inf(2)\n",
+ "acc.accepting([0, 1, 2]) = True\n",
+ "acc.accepting([1, 2]) = True\n",
+ "acc.accepting([0, 1]) = False\n",
+ "acc.accepting([0, 2]) = True\n",
+ "acc.accepting([0]) = False\n",
+ "acc.accepting([1]) = True\n",
+ "acc.accepting([2]) = True\n",
+ "acc.accepting([]) = False\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc = spot.acc_code('Fin(0) & Inf(1) | Inf(2)')\n",
+ "print(\"acc =\", acc)\n",
+ "for x in ([0, 1, 2], [1, 2], [0, 1], [0, 2], [0], [1], [2], []):\n",
+ " print(\"acc.accepting({}) = {}\".format(x, acc.accepting(x)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Finally the method `used_sets()` returns a `mark_t` with all the sets appearing in the formula:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 33,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Fin(0) & Inf(2)\n",
+ "{0,2}\n",
+ "3\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc = spot.acc_code('Fin(0) & Inf(2)')\n",
+ "print(acc)\n",
+ "print(acc.used_sets())\n",
+ "print(acc.used_sets().max_set())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# `acc_cond`\n",
+ "\n",
+ "Automata store their acceptance condition as an instance of the `acc_cond` class.\n",
+ "This class can be thought of as a pair `(n, code)`, where `n` is an integer that tells how many acceptance sets are used, while the `code` is an instance of `acc_code` and encodes the formula over *a subset* of these acceptance sets. We usually have `n == code.used_sets().max_set())`, but `n` can be larger.\n",
+ "\n",
+ "It is OK if an automaton declares that is used 3 sets, even if the acceptance condition formula only uses set number 1.\n",
+ "\n",
+ "The `acc_cond` objects are usually not created by hand: automata have dedicated methods for that. But for the purpose of this notebook, let's do it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 34,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(4, (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))"
+ ]
+ },
+ "execution_count": 34,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond(4, spot.acc_code('Rabin 2'))\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For convenience, you can pass the string directly:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(4, (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))"
+ ]
+ },
+ "execution_count": 35,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond(4, 'Rabin 2')\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "4"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc.num_sets()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))"
+ ]
+ },
+ "execution_count": 37,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc.get_acceptance()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `acc_cond` object can also be constructed using only a number of sets. In that case, the acceptance condition defaults to `t`, and it can be changed to something else later (using `set_acceptance()`). The number of acceptance sets can also be augmented with `add_sets()`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(4, t)"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond(4)\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(6, t)"
+ ]
+ },
+ "execution_count": 39,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc.add_sets(2)\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(6, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))"
+ ]
+ },
+ "execution_count": 40,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc.set_acceptance('Streett 2')\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Calling the constructor of `acc_cond` by passing just an instance of `acc_code` (or a string that will be passed to the `acc_code` constructor) will automatically set the number of acceptance sets to the minimum needed by the formula:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(4, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))"
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond('Streett 2')\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The above is in fact just syntactic sugar for:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(4, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))"
+ ]
+ },
+ "execution_count": 42,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "code = spot.acc_code('Streett 2')\n",
+ "acc = spot.acc_cond(code.used_sets().max_set(), code)\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The common scenario of setting generalized Büchi acceptance can be achieved more efficiently by first setting the number of acceptance sets, and then requiring generalized Büchi acceptance:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))"
+ ]
+ },
+ "execution_count": 43,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond(4)\n",
+ "acc.set_generalized_buchi()\n",
+ "acc"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `acc_cond` class has several methods for detecting acceptance conditions that match the named acceptance conditions of the HOA format. Note that in the HOA format, `Inf(0)&Inf(1)&Inf(2)&Inf(3)` is only called generalized Büchi if exactly 4 acceptance sets are used. So the following behavior should not be surprising:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
+ "True\n",
+ "(5, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
+ "False\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(acc)\n",
+ "print(acc.is_generalized_buchi())\n",
+ "acc.add_sets(1)\n",
+ "print(acc)\n",
+ "print(acc.is_generalized_buchi())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Similar methods like `is_t()`, `is_f()`, `is_buchi()`, `is_co_buchi()`, `is_generalized_co_buchi()` all return a Boolean.\n",
+ "\n",
+ "The `is_rabin()` and `is_streett()` methods, however, return a number of pairs. The number of pairs is always `num_sets()/2` on success, or -1 on failure."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(4, (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))\n",
+ "2\n",
+ "-1\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond('Rabin 2')\n",
+ "print(acc)\n",
+ "print(acc.is_rabin())\n",
+ "print(acc.is_streett())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The check for parity acceptance returns three Boolean in a list of the form `[matched, max?, odd?]`. If `matched` is `False`, the other values should be ignored."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(4, Fin(0) & (Inf(1) | (Fin(2) & Inf(3))))\n",
+ "[True, False, True]\n",
+ "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
+ "[False, False, False]\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond('parity min odd 4')\n",
+ "print(acc)\n",
+ "print(acc.is_parity())\n",
+ "acc.set_generalized_buchi()\n",
+ "print(acc)\n",
+ "print(acc.is_parity())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If the acceptance condition has some known name, it can be retrieved using the `name()` method. By default the name given is a human-readable string close that used in the HOA format, but with proper accents, and support for name like `Streett-like` or `Rabin-like`. The argument `arg` can specify a different style using the same syntax as in `--format='%[arg]g'` when using the command-line tools."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "generalized-Büchi 4\n",
+ "gen. Büchi 4\n",
+ "generalized-Buchi\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(acc.name())\n",
+ "print(acc.name(\"d\")) # <- Style used by print_dot(aut, \"a\")\n",
+ "print(acc.name(\"0\")) # <- no parameters"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`acc_cond` contains a few functions for manipulating `mark_t` instances, these are typically functions that require known the total number of accepting sets declared.\n",
+ "\n",
+ "For instance complementing a `mark_t`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{0,2}\n"
+ ]
+ }
+ ],
+ "source": [
+ "m = spot.mark_t([1, 3])\n",
+ "print(acc.comp(m))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "`all_sets()` returns a `mark_t` listing all the declared sets: "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{0,1,2,3}"
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "acc.all_sets()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For convencience, the `accepting()` method of `acc_cond` delegates to that of the `acc_code`. \n",
+ "Any set passed to `accepting()` that is not used by the acceptance formula has no influence."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "acc = (4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
+ "acc.accepting([0, 1, 2, 3, 10]) = True\n",
+ "acc.accepting([1, 2]) = False\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"acc =\", acc)\n",
+ "for x in ([0, 1, 2, 3, 10], [1, 2]):\n",
+ " print(\"acc.accepting({}) = {}\".format(x, acc.accepting(x)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Finally the `unsat_mark()` method of `acc_cond` computes an instance of `mark_t` that is unaccepting (i.e., passing this value to `acc.accepting(...)` will return `False` when such a value exist. Not all acceptance conditions have an satisfiable mark. Obviously the `t` acceptance is always satisfiable, and so are all equivalent acceptances (for instance `Fin(1)|Inf(1)`).\n",
+ "\n",
+ "For this reason, `unsat_mark()` actually returns a pair: `(bool, mark_t)` where the Boolean is `False` iff the acceptance is always satisfiable. When the Boolean is `True`, then the second element of the pair gives a non-accepting mark."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
+ "(True, {})\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(acc)\n",
+ "print(acc.unsat_mark())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(0, t)\n",
+ "(False, {})\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond(0) # use 0 acceptance sets, and the default formula (t)\n",
+ "print(acc)\n",
+ "print(acc.unsat_mark())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "(4, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))\n",
+ "(True, {2})\n"
+ ]
+ }
+ ],
+ "source": [
+ "acc = spot.acc_cond('Streett 2')\n",
+ "print(acc)\n",
+ "print(acc.unsat_mark())"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,1449 +1509,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "import spot\n",
- "spot.setup()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Acceptance conditions\n",
- "\n",
- "The acceptance condition of an automaton specifies which of its paths are accepting.\n",
- "\n",
- "The way acceptance conditions are stored in Spot is derived from the way acceptance conditions are specified in the [HOA format](http://adl.github.io/hoaf/). In HOA, acceptance conditions are given as a line of the form:\n",
- "\n",
- " Acceptance: 3 (Inf(0)&Fin(1))|Inf(2)\n",
- "\n",
- "The number `3` gives the number of acceptance sets used (numbered from `0` to `2` in that case), while the rest of the line is a positive Boolean formula over terms of the form:\n",
- "- `Inf(n)`, that is true if and only if the set `n` is seen infinitely often,\n",
- "- `Fin(n)`, that is true if and only if the set `n` should be seen finitely often,\n",
- "- `t`, always true,\n",
- "- `f`, always false.\n",
- "\n",
- "The HOA specifications additionally allows terms of the form `Inf(!n)` or `Fin(!n)` but Spot automatically rewrites those away when reading an HOA file.\n",
- "\n",
- "Note that the number of sets given can be larger than what is actually needed by the acceptance formula.\n",
- "\n",
- "Transitions in automata can be tagged as being part of some member sets, and a path in the automaton is accepting if the set of acceptance sets visited along this path satify the acceptance condition.\n",
- "\n",
- "Definining acceptance conditions in Spot involves three different types of C++ objects:\n",
- "\n",
- "- `spot::acc_cond` is used to represent an acceptance condition, that is: a number of sets and a formula.\n",
- "- `spot::acc_cond::acc_code`, is used to represent Boolean formula for the acceptance condition using a kind of byte code (hence the name)\n",
- "- `spot::acc_cond::mark_t`, is a type of bit-vector used to represent membership to acceptance sets.\n",
- "\n",
- "In because Swig's support for nested class is limited, these types are available respectively as `spot.acc_cond`, `spot.acc_code`, and `spot.mark_t` in Python.\n",
- "\n",
- "## `mark_t`\n",
- "\n",
- "Let's start with the simpler of these three objects. `mark_t` is a type of bit vector. Its main constructor takes a sequence of set numbers."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.mark_t()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "text": [
- "{}"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.mark_t([0, 2, 3])"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "text": [
- "{0,2,3}"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.mark_t((0, 2, 3))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "text": [
- "{0,2,3}"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As seen above, the sequence of set numbers can be specified using a list or a tuple. While from the Python language point of view, using a tuple is faster than using a list, the overhead to converting all the arguments from Python to C++ and then converting the resuslting back from C++ to Python makes this difference completely negligeable. In the following, we opted to use lists, because brackets are more readable than nested parentheses."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "x = spot.mark_t([0, 2, 3])\n",
- "y = spot.mark_t([0, 4])\n",
- "print(x | y)\n",
- "print(x & y)\n",
- "print(x - y)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{0,2,3,4}\n",
- "{0}\n",
- "{2,3}\n"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The bits can be set, cleared, and tested using the `set()`, `clear()`, and `has()` methods:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "x.set(5)\n",
- "print(x)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{0,2,3,5}\n"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "x.clear(3)\n",
- "print(x)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{0,2,5}\n"
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(x.has(2))\n",
- "print(x.has(3))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "True\n",
- "False\n"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Left-shifting will increment all set numbers.\n",
- "This operation is useful when building the product of two automata: all the set number of one automaton have to be shift by the number of sets used in the other automaton."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "x << 2"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 9,
- "text": [
- "{2,4,7}"
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Internally, the `mark_t` stores the bit-vector as an integer. This also implies that we currently do not support more than 32 acceptance sets. The underlaying integer can be retrieved using `.id`."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(x)\n",
- "print(x.id)\n",
- "print(bin(x.id))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{0,2,5}\n",
- "37\n",
- "0b100101\n"
- ]
- }
- ],
- "prompt_number": 10
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`mark_t` can also be initialized using an integer: in that case the integer is interpreted as a bit vector.\n",
- "\n",
- "A frequent error is to use `mark_t(n)` when we really mean `mark_t([n])` or `mark_t((n,))`."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "# compare\n",
- "print(spot.mark_t([5]))\n",
- "# with\n",
- "print(spot.mark_t(5))\n",
- "print(spot.mark_t(0b10101))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{5}\n",
- "{0,2}\n",
- "{0,2,4}\n"
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The different sets can be iterated over with the `sets()` method, that returns a tuble with the index of all bits set."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(x)\n",
- "print(list(x.sets()))\n",
- "for s in x.sets():\n",
- " print(s)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{0,2,5}\n",
- "[0, 2, 5]\n",
- "0\n",
- "2\n",
- "5\n"
- ]
- }
- ],
- "prompt_number": 12
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`count()` return the number of sets in a `mark_t`:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "x.count()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 13,
- "text": [
- "3"
- ]
- }
- ],
- "prompt_number": 13
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`lowest()` returns a `mark_t` containing only the lowest set number. This provides another way to iterate overs all set numbers in cases where you need the result as a `mark_t`."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.mark_t([1,3,5]).lowest()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 14,
- "text": [
- "{1}"
- ]
- }
- ],
- "prompt_number": 14
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "v = spot.mark_t([1, 3, 5])\n",
- "while v: # this stops once v is empty\n",
- " b = v.lowest()\n",
- " v -= b\n",
- " print(b)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{1}\n",
- "{3}\n",
- "{5}\n"
- ]
- }
- ],
- "prompt_number": 15
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`max_set()` returns the number of the highest set plus one. This is usually used to figure out how many sets we need to declare on the `Acceptance:` line of the HOA format:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.mark_t([1, 3, 5]).max_set()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 16,
- "text": [
- "6"
- ]
- }
- ],
- "prompt_number": 16
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## `acc_code`\n",
- "\n",
- "`acc_code` encodes the formula of the acceptance condition using a kind of bytecode that basically corresponds to an encoding in [reverse Polish notation](http://en.wikipedia.org/wiki/Reverse_Polish_notation) in which conjunctions of `Inf(n)` terms, and disjunctions of `Fin(n)` terms are grouped. In particular, the frequently-used genaralized-B\u00fcchi acceptance conditions (like `Inf(0)&Inf(1)&Inf(2)`) are always encoded as a single term (like `Inf({0,1,2})`).\n",
- "\n",
- "The simplest way to construct an `acc_code` by passing a string that represent the formula to build."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code('(Inf(0)&Fin(1))|Inf(2)')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 17,
- "text": [
- "(Inf(0) & Fin(1)) | Inf(2)"
- ]
- }
- ],
- "prompt_number": 17
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "You may also use a named acceptance condition:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code('Rabin 2')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 18,
- "text": [
- "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))"
- ]
- }
- ],
- "prompt_number": 18
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The recognized names are the valide values for `acc-name:` in the [HOA format](http://adl.github.io/hoaf/). Additionally numbers may be replaced by ranges of the form `n..m`, in which case a random number is selected in that range."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(spot.acc_code('Streett 2..4'))\n",
- "print(spot.acc_code('Streett 2..4'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(Fin(0) | Inf(1)) & (Fin(2) | Inf(3)) & (Fin(4) | Inf(5)) & (Fin(6) | Inf(7))\n",
- "(Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n"
- ]
- }
- ],
- "prompt_number": 19
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "It may also be convenient to generate a random acceptance condition:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code('random 3..5')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 20,
- "text": [
- "(Fin(3) | Inf(1)) & Inf(4) & (Fin(0)|Fin(2))"
- ]
- }
- ],
- "prompt_number": 20
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `to_cnf()` and `to_dnf()` functions can be used to rewrite the formula into Conjunctive or Disjunctive normal forms. This functions will simplify the resulting formulas to make them irredundant."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.acc_code('parity min odd 5')\n",
- "a"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 21,
- "text": [
- "Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | Fin(4))))"
- ]
- }
- ],
- "prompt_number": 21
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.to_cnf()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 22,
- "text": [
- "Fin(0) & (Inf(1) | Fin(2)) & (Inf(1) | Inf(3) | Fin(4))"
- ]
- }
- ],
- "prompt_number": 22
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.to_dnf()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 23,
- "text": [
- "(Fin(0) & Inf(1)) | (Fin(0) & Fin(2) & Inf(3)) | (Fin(0) & Fin(2) & Fin(4))"
- ]
- }
- ],
- "prompt_number": 23
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The manipulation of `acc_code` objects is quite rudimentary at the moment: it easy to build, but it's harder take appart. In fact we won't attempt to disassemble an `acc_code` object in Python: those things are better done in C++\n",
- "\n",
- "Operators `|`, `|=`, `&`, `&=`, `<<`, and `<<=` can be used with their obvious semantics.\n",
- "Whenever possible, the inplace versions (`|=`, `&=`, `<<=`) should be prefered, because they create less temporary acceptance conditions."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "x = spot.acc_code('Rabin 2')\n",
- "y = spot.acc_code('Rabin 2') << 4\n",
- "print(x)\n",
- "print(y)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
- "(Fin(4) & Inf(5)) | (Fin(6) & Inf(7))\n"
- ]
- }
- ],
- "prompt_number": 24
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(x | y)\n",
- "print(x & y)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(Fin(4) & Inf(5)) | (Fin(6) & Inf(7)) | (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
- "((Fin(4) & Inf(5)) | (Fin(6) & Inf(7))) & ((Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))\n"
- ]
- }
- ],
- "prompt_number": 25
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `complement()` method returns the complemented acceptance condition:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(x)\n",
- "print(x.complement())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
- "(Inf(0) | Fin(1)) & (Inf(2) | Fin(3))\n"
- ]
- }
- ],
- "prompt_number": 26
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Instead of using `acc_code('string')`, it is also possible to build an acceptance formula from atoms like `Inf({...})`, `Fin({...})`, `t`, or `f`.\n",
- "\n",
- "Remember that in our encoding for the formula, terms like `Inf(1)&Inf(2)` and `Fin(3)|Fin(4)|Fin(5)` are actually stored as `Inf({1,2})` and `Fin({3,4,5})`, where `{1,2}` and `{3,4,5}` are instance of `mark_t`. These terms can be generated with the\n",
- "functions `spot.acc_code.inf(mark)` and `spot.acc_code.fin(mark)`.\n",
- "\n",
- "`Inf({})` is equivalent to `t`, and `Fin({})` is equivalent to `f`, but it's better to use the functions `spot.acc_code.t()` or `spot.acc_code.f()` directly."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code.inf([1,2]) & spot.acc_code.fin([3,4,5])"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 27,
- "text": [
- "(Fin(3)|Fin(4)|Fin(5)) & (Inf(1)&Inf(2))"
- ]
- }
- ],
- "prompt_number": 27
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code.inf([])"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 28,
- "text": [
- "t"
- ]
- }
- ],
- "prompt_number": 28
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code.t()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 29,
- "text": [
- "t"
- ]
- }
- ],
- "prompt_number": 29
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code.fin([])"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 30,
- "text": [
- "f"
- ]
- }
- ],
- "prompt_number": 30
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.acc_code.f()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 31,
- "text": [
- "f"
- ]
- }
- ],
- "prompt_number": 31
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To evaluate an acceptance condition formula on a run, build a `mark_t` containing all the acceptance sets that are seen infinitely often along this run, and call the `accepting()` method."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_code('Fin(0) & Inf(1) | Inf(2)')\n",
- "print(\"acc =\", acc)\n",
- "for x in ([0, 1, 2], [1, 2], [0, 1], [0, 2], [0], [1], [2], []):\n",
- " print(\"acc.accepting({}) = {}\".format(x, acc.accepting(x)))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "acc = (Fin(0) & Inf(1)) | Inf(2)\n",
- "acc.accepting([0, 1, 2]) = True\n",
- "acc.accepting([1, 2]) = True\n",
- "acc.accepting([0, 1]) = False\n",
- "acc.accepting([0, 2]) = True\n",
- "acc.accepting([0]) = False\n",
- "acc.accepting([1]) = True\n",
- "acc.accepting([2]) = True\n",
- "acc.accepting([]) = False\n"
- ]
- }
- ],
- "prompt_number": 32
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally the method `used_sets()` returns a `mark_t` with all the sets appearing in the formula:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_code('Fin(0) & Inf(2)')\n",
- "print(acc)\n",
- "print(acc.used_sets())\n",
- "print(acc.used_sets().max_set())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "Fin(0) & Inf(2)\n",
- "{0,2}\n",
- "3\n"
- ]
- }
- ],
- "prompt_number": 33
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# `acc_cond`\n",
- "\n",
- "Automata store their acceptance condition as an instance of the `acc_cond` class.\n",
- "This class can be thought of as a pair `(n, code)`, where `n` is an integer that tells how many acceptance sets are used, while the `code` is an instance of `acc_code` and encodes the formula over *a subset* of these acceptance sets. We usually have `n == code.used_sets().max_set())`, but `n` can be larger.\n",
- "\n",
- "It is OK if an automaton declares that is used 3 sets, even if the acceptance condition formula only uses set number 1.\n",
- "\n",
- "The `acc_cond` objects are usually not created by hand: automata have dedicated methods for that. But for the purpose of this notebook, let's do it:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond(4, spot.acc_code('Rabin 2'))\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 34,
- "text": [
- "(4, (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))"
- ]
- }
- ],
- "prompt_number": 34
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For convenience, you can pass the string directly:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond(4, 'Rabin 2')\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 35,
- "text": [
- "(4, (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))"
- ]
- }
- ],
- "prompt_number": 35
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc.num_sets()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 36,
- "text": [
- "4"
- ]
- }
- ],
- "prompt_number": 36
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc.get_acceptance()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 37,
- "text": [
- "(Fin(0) & Inf(1)) | (Fin(2) & Inf(3))"
- ]
- }
- ],
- "prompt_number": 37
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `acc_cond` object can also be constructed using only a number of sets. In that case, the acceptance condition defaults to `t`, and it can be changed to something else later (using `set_acceptance()`). The number of acceptance sets can also be augmented with `add_sets()`."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond(4)\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 38,
- "text": [
- "(4, t)"
- ]
- }
- ],
- "prompt_number": 38
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc.add_sets(2)\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 39,
- "text": [
- "(6, t)"
- ]
- }
- ],
- "prompt_number": 39
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc.set_acceptance('Streett 2')\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 40,
- "text": [
- "(6, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))"
- ]
- }
- ],
- "prompt_number": 40
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Calling the constructor of `acc_cond` by passing just an instance of `acc_code` (or a string that will be passed to the `acc_code` constructor) will automatically set the number of acceptance sets to the minimum needed by the formula:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond('Streett 2')\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 41,
- "text": [
- "(4, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))"
- ]
- }
- ],
- "prompt_number": 41
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The above is in fact just syntactic sugar for:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "code = spot.acc_code('Streett 2')\n",
- "acc = spot.acc_cond(code.used_sets().max_set(), code)\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 42,
- "text": [
- "(4, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))"
- ]
- }
- ],
- "prompt_number": 42
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The common scenario of setting generalized B\u00fcchi acceptance can be achieved more efficiently by first setting the number of acceptance sets, and then requiring generalized B\u00fcchi acceptance:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond(4)\n",
- "acc.set_generalized_buchi()\n",
- "acc"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 43,
- "text": [
- "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))"
- ]
- }
- ],
- "prompt_number": 43
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `acc_cond` class has several methods for detecting acceptance conditions that match the named acceptance conditions of the HOA format. Note that in the HOA format, `Inf(0)&Inf(1)&Inf(2)&Inf(3)` is only called generalized B\u00fcchi if exactly 4 acceptance sets are used. So the following behavior should not be surprising:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(acc)\n",
- "print(acc.is_generalized_buchi())\n",
- "acc.add_sets(1)\n",
- "print(acc)\n",
- "print(acc.is_generalized_buchi())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
- "True\n",
- "(5, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
- "False\n"
- ]
- }
- ],
- "prompt_number": 44
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Similar methods like `is_t()`, `is_f()`, `is_buchi()`, `is_co_buchi()`, `is_generalized_co_buchi()` all return a Boolean.\n",
- "\n",
- "The `is_rabin()` and `is_streett()` methods, however, return a number of pairs. The number of pairs is always `num_sets()/2` on success, or -1 on failure."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond('Rabin 2')\n",
- "print(acc)\n",
- "print(acc.is_rabin())\n",
- "print(acc.is_streett())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(4, (Fin(0) & Inf(1)) | (Fin(2) & Inf(3)))\n",
- "2\n",
- "-1\n"
- ]
- }
- ],
- "prompt_number": 45
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The check for parity acceptance returns three Boolean in a list of the form `[matched, max?, odd?]`. If `matched` is `False`, the other values should be ignored."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond('parity min odd 4')\n",
- "print(acc)\n",
- "print(acc.is_parity())\n",
- "acc.set_generalized_buchi()\n",
- "print(acc)\n",
- "print(acc.is_parity())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(4, Fin(0) & (Inf(1) | (Fin(2) & Inf(3))))\n",
- "[True, False, True]\n",
- "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
- "[False, False, False]\n"
- ]
- }
- ],
- "prompt_number": 46
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If the acceptance condition has some known name, it can be retrieved using the `name()` method. By default the name given is a human-readable string close that used in the HOA format, but with proper accents, and support for name like `Streett-like` or `Rabin-like`. The argument `arg` can specify a different style using the same syntax as in `--format='%[arg]g'` when using the command-line tools."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(acc.name())\n",
- "print(acc.name(\"d\")) # <- Style used by print_dot(aut, \"a\")\n",
- "print(acc.name(\"0\")) # <- no parameters"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "generalized-B\u00fcchi 4\n",
- "gen. B\u00fcchi 4\n",
- "generalized-Buchi\n"
- ]
- }
- ],
- "prompt_number": 47
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`acc_cond` contains a few functions for manipulating `mark_t` instances, these are typically functions that require known the total number of accepting sets declared.\n",
- "\n",
- "For instance complementing a `mark_t`:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "m = spot.mark_t([1, 3])\n",
- "print(acc.comp(m))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{0,2}\n"
- ]
- }
- ],
- "prompt_number": 48
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`all_sets()` returns a `mark_t` listing all the declared sets: "
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc.all_sets()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 49,
- "text": [
- "{0,1,2,3}"
- ]
- }
- ],
- "prompt_number": 49
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For convencience, the `accepting()` method of `acc_cond` delegates to that of the `acc_code`. \n",
- "Any set passed to `accepting()` that is not used by the acceptance formula has no influence."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(\"acc =\", acc)\n",
- "for x in ([0, 1, 2, 3, 10], [1, 2]):\n",
- " print(\"acc.accepting({}) = {}\".format(x, acc.accepting(x)))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "acc = (4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
- "acc.accepting([0, 1, 2, 3, 10]) = True\n",
- "acc.accepting([1, 2]) = False\n"
- ]
- }
- ],
- "prompt_number": 50
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally the `unsat_mark()` method of `acc_cond` computes an instance of `mark_t` that is unaccepting (i.e., passing this value to `acc.accepting(...)` will return `False` when such a value exist. Not all acceptance conditions have an satisfiable mark. Obviously the `t` acceptance is always satisfiable, and so are all equivalent acceptances (for instance `Fin(1)|Inf(1)`).\n",
- "\n",
- "For this reason, `unsat_mark()` actually returns a pair: `(bool, mark_t)` where the Boolean is `False` iff the acceptance is always satisfiable. When the Boolean is `True`, then the second element of the pair gives a non-accepting mark."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(acc)\n",
- "print(acc.unsat_mark())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(4, Inf(0)&Inf(1)&Inf(2)&Inf(3))\n",
- "(True, {})\n"
- ]
- }
- ],
- "prompt_number": 51
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond(0) # use 0 acceptance sets, and the default formula (t)\n",
- "print(acc)\n",
- "print(acc.unsat_mark())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(0, t)\n",
- "(False, {})\n"
- ]
- }
- ],
- "prompt_number": 52
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "acc = spot.acc_cond('Streett 2')\n",
- "print(acc)\n",
- "print(acc.unsat_mark())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "(4, (Fin(0) | Inf(1)) & (Fin(2) | Inf(3)))\n",
- "(True, {2})\n"
- ]
- }
- ],
- "prompt_number": 53
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/accparse.ipynb b/tests/python/accparse.ipynb
index 734e3e848..bb6518461 100644
--- a/tests/python/accparse.ipynb
+++ b/tests/python/accparse.ipynb
@@ -1,4 +1,157 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "spot.setup()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Inf(0) & Fin(1)) | (Inf(2) & Fin(3))"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "c = spot.acc_code('Inf(0)&Fin(1)|Inf(2)&Fin(3)'); c"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Fin(1) & Inf(0)) | (Fin(3) & Inf(2))"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "c.to_dnf()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(Inf(0) | Inf(2)) & (Inf(0) | Fin(3)) & (Inf(2) | Fin(1)) & (Fin(1)|Fin(3))"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "c.to_cnf()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "all: t\n",
+ "t: t\n",
+ "Buchi: Inf(0)\n",
+ "generalized-Buchi 3: Inf(0)&Inf(1)&Inf(2)\n",
+ "generalized-Buchi 0: t\n",
+ "co-Buchi: Fin(0)\n",
+ "generalized-co-Buchi 3: Fin(0)|Fin(1)|Fin(2)\n",
+ "generalized-co-Buchi 0: f\n",
+ "Rabin 2: (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
+ "Rabin 0: f\n",
+ "Streett 2: (Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n",
+ "Streett 0: t\n",
+ "generalized-Rabin 3 1 2 3: (Fin(0) & Inf(1)) | (Fin(2) & (Inf(3)&Inf(4))) | (Fin(5) & (Inf(6)&Inf(7)&Inf(8)))\n",
+ "generalized-Rabin 0: f\n",
+ "parity min even 6: Inf(0) | (Fin(1) & (Inf(2) | (Fin(3) & (Inf(4) | Fin(5)))))\n",
+ "parity max odd 6: Inf(5) | (Fin(4) & (Inf(3) | (Fin(2) & (Inf(1) | Fin(0)))))\n",
+ "parity max even 6: Fin(5) & (Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0)))))\n",
+ "parity min odd 6: Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | (Fin(4) & Inf(5)))))\n",
+ "parity min even 5: Inf(0) | (Fin(1) & (Inf(2) | (Fin(3) & Inf(4))))\n",
+ "parity max odd 5: Fin(4) & (Inf(3) | (Fin(2) & (Inf(1) | Fin(0))))\n",
+ "parity max even 5: Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0))))\n",
+ "parity min odd 5: Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | Fin(4))))\n",
+ "parity min even 2: Inf(0) | Fin(1)\n",
+ "parity max odd 2: Inf(1) | Fin(0)\n",
+ "parity max even 2: Fin(1) & Inf(0)\n",
+ "parity min odd 2: Fin(0) & Inf(1)\n",
+ "parity min even 1: Inf(0)\n",
+ "parity max odd 1: Fin(0)\n",
+ "parity max even 1: Inf(0)\n",
+ "parity min odd 1: Fin(0)\n",
+ "parity min even 0: t\n",
+ "parity max odd 0: t\n",
+ "parity max even 0: f\n",
+ "parity min odd 0: f\n"
+ ]
+ }
+ ],
+ "source": [
+ "for acc in ['all', 't', \n",
+ " 'Buchi', 'generalized-Buchi 3', 'generalized-Buchi 0',\n",
+ " 'co-Buchi', 'generalized-co-Buchi 3', 'generalized-co-Buchi 0',\n",
+ " 'Rabin 2', 'Rabin 0',\n",
+ " 'Streett 2', 'Streett 0',\n",
+ " 'generalized-Rabin 3 1 2 3', 'generalized-Rabin 0',\n",
+ " 'parity min even 6', 'parity max odd 6', 'parity max even 6', 'parity min odd 6',\n",
+ " 'parity min even 5', 'parity max odd 5', 'parity max even 5', 'parity min odd 5',\n",
+ " 'parity min even 2', 'parity max odd 2', 'parity max even 2', 'parity min odd 2',\n",
+ " 'parity min even 1', 'parity max odd 1', 'parity max even 1', 'parity min odd 1',\n",
+ " 'parity min even 0', 'parity max odd 0', 'parity max even 0', 'parity min odd 0',\n",
+ " ]:\n",
+ " print(acc, ': ', spot.acc_code(acc), sep='')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": []
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,161 +169,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.3+"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "import spot\n",
- "spot.setup()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "c = spot.acc_code('Inf(0)&Fin(1)|Inf(2)&Fin(3)'); c"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "text": [
- "(Inf(0) & Fin(1)) | (Inf(2) & Fin(3))"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "c.to_dnf()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "text": [
- "(Fin(1) & Inf(0)) | (Fin(3) & Inf(2))"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "c.to_cnf()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "text": [
- "(Inf(0) | Inf(2)) & (Inf(0) | Fin(3)) & (Inf(2) | Fin(1)) & (Fin(1)|Fin(3))"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for acc in ['all', 't', \n",
- " 'Buchi', 'generalized-Buchi 3', 'generalized-Buchi 0',\n",
- " 'co-Buchi', 'generalized-co-Buchi 3', 'generalized-co-Buchi 0',\n",
- " 'Rabin 2', 'Rabin 0',\n",
- " 'Streett 2', 'Streett 0',\n",
- " 'generalized-Rabin 3 1 2 3', 'generalized-Rabin 0',\n",
- " 'parity min even 6', 'parity max odd 6', 'parity max even 6', 'parity min odd 6',\n",
- " 'parity min even 5', 'parity max odd 5', 'parity max even 5', 'parity min odd 5',\n",
- " 'parity min even 2', 'parity max odd 2', 'parity max even 2', 'parity min odd 2',\n",
- " 'parity min even 1', 'parity max odd 1', 'parity max even 1', 'parity min odd 1',\n",
- " 'parity min even 0', 'parity max odd 0', 'parity max even 0', 'parity min odd 0',\n",
- " ]:\n",
- " print(acc, ': ', spot.acc_code(acc), sep='')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "all: t\n",
- "t: t\n",
- "Buchi: Inf(0)\n",
- "generalized-Buchi 3: Inf(0)&Inf(1)&Inf(2)\n",
- "generalized-Buchi 0: t\n",
- "co-Buchi: Fin(0)\n",
- "generalized-co-Buchi 3: Fin(0)|Fin(1)|Fin(2)\n",
- "generalized-co-Buchi 0: f\n",
- "Rabin 2: (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
- "Rabin 0: f\n",
- "Streett 2: (Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n",
- "Streett 0: t\n",
- "generalized-Rabin 3 1 2 3: (Fin(0) & Inf(1)) | (Fin(2) & (Inf(3)&Inf(4))) | (Fin(5) & (Inf(6)&Inf(7)&Inf(8)))\n",
- "generalized-Rabin 0: f\n",
- "parity min even 6: Inf(0) | (Fin(1) & (Inf(2) | (Fin(3) & (Inf(4) | Fin(5)))))\n",
- "parity max odd 6: Inf(5) | (Fin(4) & (Inf(3) | (Fin(2) & (Inf(1) | Fin(0)))))\n",
- "parity max even 6: Fin(5) & (Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0)))))\n",
- "parity min odd 6: Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | (Fin(4) & Inf(5)))))\n",
- "parity min even 5: Inf(0) | (Fin(1) & (Inf(2) | (Fin(3) & Inf(4))))\n",
- "parity max odd 5: Fin(4) & (Inf(3) | (Fin(2) & (Inf(1) | Fin(0))))\n",
- "parity max even 5: Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0))))\n",
- "parity min odd 5: Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | Fin(4))))\n",
- "parity min even 2: Inf(0) | Fin(1)\n",
- "parity max odd 2: Inf(1) | Fin(0)\n",
- "parity max even 2: Fin(1) & Inf(0)\n",
- "parity min odd 2: Fin(0) & Inf(1)\n",
- "parity min even 1: Inf(0)\n",
- "parity max odd 1: Fin(0)\n",
- "parity max even 1: Inf(0)\n",
- "parity min odd 1: Fin(0)\n",
- "parity min even 0: t\n",
- "parity max odd 0: t\n",
- "parity max even 0: f\n",
- "parity min odd 0: f\n"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 5
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/alternation.ipynb b/tests/python/alternation.ipynb
index 4e8ca2119..cc49de118 100644
--- a/tests/python/alternation.ipynb
+++ b/tests/python/alternation.ipynb
@@ -1,4 +1,1807 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "spot.setup(show_default='.ba')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "These test cases for the `remove_alternation()` algorithm."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.automaton('''\n",
+ "HOA: v1\n",
+ "tool: \"ltl3ba\" \"1.1.3\"\n",
+ "name: \"VWAA for FGa && GFb\"\n",
+ "States: 6\n",
+ "Start: 0\n",
+ "acc-name: co-Buchi\n",
+ "Acceptance: 1 Fin(0)\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "properties: trans-labels explicit-labels state-acc univ-branch very-weak\n",
+ "--BODY--\n",
+ "State: 0 \"(FG(a) && GF(b))\"\n",
+ " [t] 3&1\n",
+ "State: 1 \"GF(b)\"\n",
+ " [(1)] 1\n",
+ " [(!1)] 2&1\n",
+ "State: 2 \"F(b)\" {0}\n",
+ " [(1)] 5\n",
+ " [(!1)] 2\n",
+ "State: 3 \"FG(a)\" {0}\n",
+ " [(0)] 4\n",
+ " [t] 3\n",
+ "State: 4 \"G(a)\"\n",
+ " [(0)] 4\n",
+ "State: 5 \"t\"\n",
+ " [t] 5\n",
+ "--END--\n",
+ "'''); aut.show('.1ab')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fc7e0> >"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut2 = spot.remove_alternation(aut, True); aut2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fc1e0> >"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.scc_filter(aut2, True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Example from ADL's PSL2TGBA talk.\n",
+ "aut = spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 3\n",
+ "Start: 0\n",
+ "acc-name: co-Buchi\n",
+ "Acceptance: 1 Fin(0)\n",
+ "AP: 3 \"a\" \"b\" \"p\"\n",
+ "--BODY--\n",
+ "State: 0 \"(a;a*;b)*\" {0}\n",
+ " [0] 1\n",
+ " [!0] 2\n",
+ "State: 1 \"a*;b;(a;a*;b)*\" {0}\n",
+ " [0&1&2] 0&1\n",
+ " [!1&2] 1\n",
+ " [!0&!1] 2\n",
+ " [!0&1&2] 0\n",
+ "State: 2\n",
+ " [t] 2\n",
+ "--END--\n",
+ "'''); aut.show('.1ab')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fc630> >"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.remove_alternation(aut, True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 5\n",
+ "Start: 3\n",
+ "acc-name: co-Buchi\n",
+ "Acceptance: 1 Fin(0)\n",
+ "AP: 3 \"a\" \"b\" \"p\"\n",
+ "--BODY--\n",
+ "State: 0 \"(a;a*;b)*\" {0}\n",
+ " [0] 1\n",
+ " [!0] 2\n",
+ "State: 1 \"a*;b;(a;a*;b)*\" {0}\n",
+ " [0&1&2] 0&1\n",
+ " [!1&2] 1\n",
+ " [!0&!1] 2\n",
+ " [!0&1&2] 0\n",
+ "State: 2\n",
+ " [t] 2\n",
+ "State: 3\n",
+ " [0] 4&0\n",
+ "State: 4\n",
+ " [t] 3\n",
+ "--END--\n",
+ "'''); aut.show('.1ab')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fc6f0> >"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.remove_alternation(aut, True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Example from ADL's PSL2TGBA talk.\n",
+ "aut = spot.automaton('''\n",
+ "HOA: v1\n",
+ "States: 6\n",
+ "Start: 0&3\n",
+ "Acceptance: 1 Fin(0)\n",
+ "AP: 3 \"a\" \"b\" \"p\"\n",
+ "--BODY--\n",
+ "State: 0 \"(a;a*;b)*\" {0}\n",
+ " [0] 1\n",
+ " [!0] 2\n",
+ "State: 1 \"a*;b;(a;a*;b)*\" {0}\n",
+ " [0&1&2] 0&1\n",
+ " [!1&2] 1\n",
+ " [!0&!1] 2\n",
+ " [!0&1&2] 0\n",
+ "State: 2\n",
+ " [t] 2\n",
+ "State: 3\n",
+ " [0] 3\n",
+ " [!0] 3&4\n",
+ "State: 4 {0}\n",
+ " [!0] 4\n",
+ " [0] 5\n",
+ "State: 5\n",
+ " [t] 5\n",
+ "--END--\n",
+ "'''); aut.show('.1ab')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fc7b0> >"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.remove_alternation(aut, True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fcae0> >"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = spot.automaton('''\n",
+ "HOA: v1\n",
+ "tool: \"ltl3dra\" \"0.2.2\"\n",
+ "name: \"VWAA for GFa\"\n",
+ "States: 3\n",
+ "Start: 0\n",
+ "acc-name: co-Buchi\n",
+ "Acceptance: 1 Fin(0)\n",
+ "AP: 1 \"a\"\n",
+ "properties: trans-labels explicit-labels state-acc univ-branch very-weak\n",
+ "--BODY--\n",
+ "State: 0 \"GF(a)\"\n",
+ " [t] 1&0\n",
+ "State: 1 \"F(a)\" {0}\n",
+ " [(0)] 2\n",
+ " [t] 1\n",
+ "State: 2 \"t\"\n",
+ " [t] 2\n",
+ "--END--\n",
+ "'''); a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f79685fc840> >"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.remove_alternation(a, True)"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,1795 +1819,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "import spot\n",
- "spot.setup(show_default='.ba')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "These test cases for the `remove_alternation()` algorithm."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.automaton('''\n",
- "HOA: v1\n",
- "tool: \"ltl3ba\" \"1.1.3\"\n",
- "name: \"VWAA for FGa && GFb\"\n",
- "States: 6\n",
- "Start: 0\n",
- "acc-name: co-Buchi\n",
- "Acceptance: 1 Fin(0)\n",
- "AP: 2 \"a\" \"b\"\n",
- "properties: trans-labels explicit-labels state-acc univ-branch very-weak\n",
- "--BODY--\n",
- "State: 0 \"(FG(a) && GF(b))\"\n",
- " [t] 3&1\n",
- "State: 1 \"GF(b)\"\n",
- " [(1)] 1\n",
- " [(!1)] 2&1\n",
- "State: 2 \"F(b)\" {0}\n",
- " [(1)] 5\n",
- " [(!1)] 2\n",
- "State: 3 \"FG(a)\" {0}\n",
- " [(0)] 4\n",
- " [t] 3\n",
- "State: 4 \"G(a)\"\n",
- " [(0)] 4\n",
- "State: 5 \"t\"\n",
- " [t] 5\n",
- "--END--\n",
- "'''); aut.show('.1ab')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut2 = spot.remove_alternation(aut, True); aut2"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fc7e0> >"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.scc_filter(aut2, True)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fc1e0> >"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "# Example from ADL's PSL2TGBA talk.\n",
- "aut = spot.automaton('''\n",
- "HOA: v1\n",
- "States: 3\n",
- "Start: 0\n",
- "acc-name: co-Buchi\n",
- "Acceptance: 1 Fin(0)\n",
- "AP: 3 \"a\" \"b\" \"p\"\n",
- "--BODY--\n",
- "State: 0 \"(a;a*;b)*\" {0}\n",
- " [0] 1\n",
- " [!0] 2\n",
- "State: 1 \"a*;b;(a;a*;b)*\" {0}\n",
- " [0&1&2] 0&1\n",
- " [!1&2] 1\n",
- " [!0&!1] 2\n",
- " [!0&1&2] 0\n",
- "State: 2\n",
- " [t] 2\n",
- "--END--\n",
- "'''); aut.show('.1ab')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.remove_alternation(aut, True)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fc630> >"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.automaton('''\n",
- "HOA: v1\n",
- "States: 5\n",
- "Start: 3\n",
- "acc-name: co-Buchi\n",
- "Acceptance: 1 Fin(0)\n",
- "AP: 3 \"a\" \"b\" \"p\"\n",
- "--BODY--\n",
- "State: 0 \"(a;a*;b)*\" {0}\n",
- " [0] 1\n",
- " [!0] 2\n",
- "State: 1 \"a*;b;(a;a*;b)*\" {0}\n",
- " [0&1&2] 0&1\n",
- " [!1&2] 1\n",
- " [!0&!1] 2\n",
- " [!0&1&2] 0\n",
- "State: 2\n",
- " [t] 2\n",
- "State: 3\n",
- " [0] 4&0\n",
- "State: 4\n",
- " [t] 3\n",
- "--END--\n",
- "'''); aut.show('.1ab')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 7,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.remove_alternation(aut, True)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 8,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fc6f0> >"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "# Example from ADL's PSL2TGBA talk.\n",
- "aut = spot.automaton('''\n",
- "HOA: v1\n",
- "States: 6\n",
- "Start: 0&3\n",
- "Acceptance: 1 Fin(0)\n",
- "AP: 3 \"a\" \"b\" \"p\"\n",
- "--BODY--\n",
- "State: 0 \"(a;a*;b)*\" {0}\n",
- " [0] 1\n",
- " [!0] 2\n",
- "State: 1 \"a*;b;(a;a*;b)*\" {0}\n",
- " [0&1&2] 0&1\n",
- " [!1&2] 1\n",
- " [!0&!1] 2\n",
- " [!0&1&2] 0\n",
- "State: 2\n",
- " [t] 2\n",
- "State: 3\n",
- " [0] 3\n",
- " [!0] 3&4\n",
- "State: 4 {0}\n",
- " [!0] 4\n",
- " [0] 5\n",
- "State: 5\n",
- " [t] 5\n",
- "--END--\n",
- "'''); aut.show('.1ab')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 9,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.remove_alternation(aut, True)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 10,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fc7b0> >"
- ]
- }
- ],
- "prompt_number": 10
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.automaton('''\n",
- "HOA: v1\n",
- "tool: \"ltl3dra\" \"0.2.2\"\n",
- "name: \"VWAA for GFa\"\n",
- "States: 3\n",
- "Start: 0\n",
- "acc-name: co-Buchi\n",
- "Acceptance: 1 Fin(0)\n",
- "AP: 1 \"a\"\n",
- "properties: trans-labels explicit-labels state-acc univ-branch very-weak\n",
- "--BODY--\n",
- "State: 0 \"GF(a)\"\n",
- " [t] 1&0\n",
- "State: 1 \"F(a)\" {0}\n",
- " [(0)] 2\n",
- " [t] 1\n",
- "State: 2 \"t\"\n",
- " [t] 2\n",
- "--END--\n",
- "'''); a"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 11,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fcae0> >"
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.remove_alternation(a, True)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 12,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f79685fc840> >"
- ]
- }
- ],
- "prompt_number": 12
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/atva16-fig2a.ipynb b/tests/python/atva16-fig2a.ipynb
index 0e0e3038a..08fa4509e 100644
--- a/tests/python/atva16-fig2a.ipynb
+++ b/tests/python/atva16-fig2a.ipynb
@@ -1,4 +1,228 @@
{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This example is the left part of Fig.2 in our ATVA'16 paper titled \"*Spot 2.0 — a framework for LTL and ω-automata manipulation*\"."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "spot.setup(show_default='.abr')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} \\mathsf{F} a \\leftrightarrow \\mathsf{G} \\mathsf{F} b$"
+ ],
+ "text/plain": [
+ "GFa <-> GFb"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f = spot.formula('GFa <-> GFb'); f"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f0d2406cc00> >"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f.translate()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def implies(f, g):\n",
+ " f = spot.formula(f)\n",
+ " g = spot.formula_Not(spot.formula(g))\n",
+ " return spot.product(f.translate(), g.translate()).is_empty()\n",
+ "def equiv(f, g):\n",
+ " return implies(f, g) and implies(g, f)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "equiv('a U (b U a)', 'b U a')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "equiv('!(a U b)', '!a U !b')"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,230 +240,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This example is the left part of Fig.2 in our ATVA'16 paper titled \"*Spot 2.0 \u2014 a framework for LTL and \u03c9-automata manipulation*\"."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "import spot\n",
- "spot.setup(show_default='.abr')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f = spot.formula('GFa <-> GFb'); f"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$\\mathsf{G} \\mathsf{F} a \\leftrightarrow \\mathsf{G} \\mathsf{F} b$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "text": [
- "GFa <-> GFb"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f.translate()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f0d2406cc00> >"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "def implies(f, g):\n",
- " f = spot.formula(f)\n",
- " g = spot.formula_Not(spot.formula(g))\n",
- " return spot.product(f.translate(), g.translate()).is_empty()\n",
- "def equiv(f, g):\n",
- " return implies(f, g) and implies(g, f)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 4
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "equiv('a U (b U a)', 'b U a')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "text": [
- "True"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "equiv('!(a U b)', '!a U !b')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "text": [
- "False"
- ]
- }
- ],
- "prompt_number": 6
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/atva16-fig2b.ipynb b/tests/python/atva16-fig2b.ipynb
index f896ac9de..7184ea66f 100644
--- a/tests/python/atva16-fig2b.ipynb
+++ b/tests/python/atva16-fig2b.ipynb
@@ -1,4 +1,322 @@
{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This example is the right part of Fig.2 in our ATVA'16 paper titled \"*Spot 2.0 — a framework for LTL and ω-automata manipulation*\"."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "import spot.ltsmin\n",
+ "spot.setup(show_default='.abr', max_states=10)\n",
+ "# This extra line ensures that our test-suite skips this test if divine is not installed.\n",
+ "spot.ltsmin.require('divine')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "%%dve adding\n",
+ "int c=1, x1, x2;\n",
+ "process a1 {\n",
+ " state Q, R, S; init Q;\n",
+ " trans Q -> R { guard c<20; effect x1 = c; },\n",
+ " R -> S { effect x1 = x1 + c; },\n",
+ " S -> Q { effect c = x1; };\n",
+ "}\n",
+ "process a2 {\n",
+ " state Q, R, S; init Q;\n",
+ " trans Q -> R { guard c<20; effect x2 = c; },\n",
+ " R -> S { effect x2 = x2 + c; },\n",
+ " S -> Q { effect c = x2; };\n",
+ "}\n",
+ "system async;"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "ltsmin model with the following variables:\n",
+ " c: int\n",
+ " x1: int\n",
+ " x2: int\n",
+ " a1: ['Q', 'R', 'S']\n",
+ " a2: ['Q', 'R', 'S']"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "adding"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb770097600> >"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "adding.kripke(['a1.Q', 'c==17'])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "def model_check(model, f):\n",
+ " f = spot.formula(f)\n",
+ " ss = model.kripke(spot.atomic_prop_collect(f))\n",
+ " nf = spot.formula_Not(f).translate()\n",
+ " return spot.otf_product(ss, nf).is_empty()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "model_check(adding, 'F(\"c==2\")')"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,326 +334,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This example is the right part of Fig.2 in our ATVA'16 paper titled \"*Spot 2.0 \u2014 a framework for LTL and \u03c9-automata manipulation*\"."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "import spot\n",
- "import spot.ltsmin\n",
- "spot.setup(show_default='.abr', max_states=10)\n",
- "# This extra line ensures that our test-suite skips this test if divine is not installed.\n",
- "spot.ltsmin.require('divine')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "%%dve adding\n",
- "int c=1, x1, x2;\n",
- "process a1 {\n",
- " state Q, R, S; init Q;\n",
- " trans Q -> R { guard c<20; effect x1 = c; },\n",
- " R -> S { effect x1 = x1 + c; },\n",
- " S -> Q { effect c = x1; };\n",
- "}\n",
- "process a2 {\n",
- " state Q, R, S; init Q;\n",
- " trans Q -> R { guard c<20; effect x2 = c; },\n",
- " R -> S { effect x2 = x2 + c; },\n",
- " S -> Q { effect c = x2; };\n",
- "}\n",
- "system async;"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "adding"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "text": [
- "ltsmin model with the following variables:\n",
- " c: int\n",
- " x1: int\n",
- " x2: int\n",
- " a1: ['Q', 'R', 'S']\n",
- " a2: ['Q', 'R', 'S']"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "adding.kripke(['a1.Q', 'c==17'])"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb770097600> >"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "def model_check(model, f):\n",
- " f = spot.formula(f)\n",
- " ss = model.kripke(spot.atomic_prop_collect(f))\n",
- " nf = spot.formula_Not(f).translate()\n",
- " return spot.otf_product(ss, nf).is_empty()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 5
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "model_check(adding, 'F(\"c==2\")')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "text": [
- "True"
- ]
- }
- ],
- "prompt_number": 6
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/automata-io.ipynb b/tests/python/automata-io.ipynb
index 25adc2ee7..9304361d0 100644
--- a/tests/python/automata-io.ipynb
+++ b/tests/python/automata-io.ipynb
@@ -1,4 +1,829 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.display import display\n",
+ "import spot\n",
+ "spot.setup()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "acc-name: Buchi\n",
+ "Acceptance: 1 Inf(0)\n",
+ "properties: trans-labels explicit-labels state-acc deterministic\n",
+ "properties: stutter-invariant terminal\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0\n",
+ "State: 1\n",
+ "[1] 0\n",
+ "[0&!1] 1\n",
+ "--END--\n",
+ "never {\n",
+ "T0_init:\n",
+ " if\n",
+ " :: (b) -> goto accept_all\n",
+ " :: ((a) && (!(b))) -> goto T0_init\n",
+ " fi;\n",
+ "accept_all:\n",
+ " skip\n",
+ "}\n",
+ "\n",
+ "digraph G {\n",
+ " rankdir=LR\n",
+ " node [shape=\"circle\"]\n",
+ " node [style=\"filled\", fillcolor=\"#ffffaa\"]\n",
+ " fontname=\"Lato\"\n",
+ " node [fontname=\"Lato\"]\n",
+ " edge [fontname=\"Lato\"]\n",
+ " size=\"10.2,5\" edge[arrowhead=vee, arrowsize=.7]\n",
+ " I [label=\"\", style=invis, width=0]\n",
+ " I -> 1\n",
+ " 0 [label=<0>, peripheries=2]\n",
+ " 0 -> 0 [label=<1>]\n",
+ " 1 [label=<1>]\n",
+ " 1 -> 0 [label=]\n",
+ " 1 -> 1 [label=]\n",
+ "}\n",
+ "\n",
+ "2 1\n",
+ "0 1 -1\n",
+ "1 \"b\"\n",
+ "0 & \"a\" ! \"b\"\n",
+ "-1\n",
+ "1 0 0 -1\n",
+ "1 t\n",
+ "-1\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "a = spot.translate('a U b')\n",
+ "for fmt in ('hoa', 'spin', 'dot', 'lbtt'):\n",
+ " print(a.to_str(fmt))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c050a20> >"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.save('example.aut').save('example.aut', format='lbtt', append=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "HOA: v1\r\n",
+ "States: 2\r\n",
+ "Start: 1\r\n",
+ "AP: 2 \"a\" \"b\"\r\n",
+ "acc-name: Buchi\r\n",
+ "Acceptance: 1 Inf(0)\r\n",
+ "properties: trans-labels explicit-labels state-acc deterministic\r\n",
+ "properties: stutter-invariant terminal\r\n",
+ "--BODY--\r\n",
+ "State: 0 {0}\r\n",
+ "[t] 0\r\n",
+ "State: 1\r\n",
+ "[1] 0\r\n",
+ "[0&!1] 1\r\n",
+ "--END--\r\n",
+ "2 1\r\n",
+ "0 1 -1\r\n",
+ "1 \"b\"\r\n",
+ "0 & \"a\" ! \"b\"\r\n",
+ "-1\r\n",
+ "1 0 0 -1\r\n",
+ "1 t\r\n",
+ "-1\r\n"
+ ]
+ }
+ ],
+ "source": [
+ "!cat example.aut"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195f3ecab0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c050960> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for a in spot.automata('example.aut'):\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Test `--ABORT--`\n",
+ "----------------"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting example.aut\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%file example.aut\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "acc-name: Buchi\n",
+ "Acceptance: 1 Inf(0)\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0\n",
+ "--ABORT-- /* the previous automaton should be ignored */\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Inf(0)\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0\n",
+ "State: 1\n",
+ "[1] 0\n",
+ "[0&!1] 1\n",
+ "--END--"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c050a50> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for a in spot.automata('example.aut'):\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c086120> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c050900> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for a in spot.automata(\"\"\"\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 1\n",
+ "name: \"Hello world\"\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Inf(0)\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0\n",
+ "State: 1\n",
+ "[1] 0\n",
+ "[0&!1] 1\n",
+ "--END--\n",
+ "HOA: v1\n",
+ "States: 1\n",
+ "Start: 0\n",
+ "name: \"Hello world 2\"\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 2 Inf(0)&Inf(1)\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0 {1}\n",
+ "[0&!1] 0\n",
+ "--END--\n",
+ "\"\"\"):\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Test syntax errors\n",
+ "------------------"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting example.aut\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%file example.aut\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "acc-name: Buchi\n",
+ "Acceptance: 1 Inf(0)\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 1\n",
+ "State: 1\n",
+ "[t] 1\n",
+ "--END--\n",
+ "HOA: v1\n",
+ "States: 2\n",
+ "Start: 1\n",
+ "AP: 2 \"a\" \"b\"\n",
+ "Acceptance: 1 Inf(0)\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[a] 3\n",
+ "State: 1\n",
+ "[1] 0\n",
+ "[0&!1] 1\n",
+ "--END--"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c0860c0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "ename": "SyntaxError",
+ "evalue": "\nexample.aut:20.2: syntax error, unexpected identifier\nexample.aut:20.1-3: ignoring this invalid label\nexample.aut:20.5: state number is larger than state count...\nexample.aut:14.1-9: ... declared here.\n ()",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32munknown\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m \nexample.aut:20.2: syntax error, unexpected identifier\nexample.aut:20.1-3: ignoring this invalid label\nexample.aut:20.5: state number is larger than state count...\nexample.aut:14.1-9: ... declared here.\n\n"
+ ]
+ }
+ ],
+ "source": [
+ "for a in spot.automata('example.aut'):\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7f195c086600> >"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.automaton('example.aut', timeout=100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "CalledProcessError",
+ "evalue": "Command 'non-existing-cmd ' returned non-zero exit status 127.",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'non-existing-cmd |'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 479\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 480\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 481\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 482\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 483\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, ignore_abort, trust_hoa, no_sid, debug, *sources)\u001b[0m\n\u001b[1;32m 464\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 465\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 466\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 467\u001b[0m \u001b[0;31m# deleting o explicitely now prevents Python 3.5 from\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 468\u001b[0m \u001b[0;31m# reporting the following error: \"\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sleep 3; cat example.aut |'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 479\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 480\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 481\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 482\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 483\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, ignore_abort, trust_hoa, no_sid, debug, *sources)\u001b[0m\n\u001b[1;32m 423\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 424\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 425\u001b[0;31m \u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcommunicate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 426\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTimeoutExpired\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 427\u001b[0m \u001b[0;31m# Using subprocess.check_output() with timeout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36mcommunicate\u001b[0;34m(self, input, timeout)\u001b[0m\n\u001b[1;32m 841\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 842\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 843\u001b[0;31m \u001b[0mstdout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstderr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_communicate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mendtime\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 844\u001b[0m \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 845\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_communication_started\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m_communicate\u001b[0;34m(self, input, endtime, orig_timeout)\u001b[0m\n\u001b[1;32m 1513\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1514\u001b[0m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mselector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1515\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_check_timeout\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mendtime\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morig_timeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1516\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1517\u001b[0m \u001b[0;31m# XXX Rewrite these to use non-blocking I/O on the file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;32m/usr/lib/python3.6/subprocess.py\u001b[0m in \u001b[0;36m_check_timeout\u001b[0;34m(self, endtime, orig_timeout)\u001b[0m\n\u001b[1;32m 869\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 870\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m_time\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0mendtime\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 871\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTimeoutExpired\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morig_timeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 872\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 873\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+ "\u001b[0;31mTimeoutExpired\u001b[0m: Command 'sleep 3; cat example.aut ' timed out after 1 seconds"
+ ]
+ }
+ ],
+ "source": [
+ "spot.automaton('sleep 3; cat example.aut |', timeout=1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "rm example.aut"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -15,851 +840,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.4.3+"
- },
- "name": "",
- "signature": "sha256:d9763e3af9f29bca127bdbfb9c6b0bcfaf276a0c32d9f789d696bfbe4a563e57"
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "from IPython.display import display\n",
- "import spot\n",
- "spot.setup()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.translate('a U b')\n",
- "for fmt in ('hoa', 'spin', 'dot', 'lbtt'):\n",
- " print(a.to_str(fmt))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "HOA: v1\n",
- "States: 2\n",
- "Start: 1\n",
- "AP: 2 \"a\" \"b\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 1 Inf(0)\n",
- "properties: trans-labels explicit-labels state-acc deterministic\n",
- "properties: stutter-invariant terminal\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0\n",
- "State: 1\n",
- "[1] 0\n",
- "[0&!1] 1\n",
- "--END--\n",
- "never {\n",
- "T0_init:\n",
- " if\n",
- " :: (b) -> goto accept_all\n",
- " :: ((a) && (!(b))) -> goto T0_init\n",
- " fi;\n",
- "accept_all:\n",
- " skip\n",
- "}\n",
- "\n",
- "digraph G {\n",
- " rankdir=LR\n",
- " node [shape=\"circle\"]\n",
- " node [style=\"filled\", fillcolor=\"#ffffaa\"]\n",
- " fontname=\"Lato\"\n",
- " node [fontname=\"Lato\"]\n",
- " edge [fontname=\"Lato\"]\n",
- " size=\"10.2,5\" edge[arrowhead=vee, arrowsize=.7]\n",
- " I [label=\"\", style=invis, width=0]\n",
- " I -> 1\n",
- " 0 [label=<0>, peripheries=2]\n",
- " 0 -> 0 [label=<1>]\n",
- " 1 [label=<1>]\n",
- " 1 -> 0 [label=]\n",
- " 1 -> 1 [label=]\n",
- "}\n",
- "\n",
- "2 1\n",
- "0 1 -1\n",
- "1 \"b\"\n",
- "0 & \"a\" ! \"b\"\n",
- "-1\n",
- "1 0 0 -1\n",
- "1 t\n",
- "-1\n",
- "\n"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.save('example.aut').save('example.aut', format='lbtt', append=True)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201e0810> >"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "!cat example.aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "HOA: v1\r\n",
- "States: 2\r\n",
- "Start: 1\r\n",
- "AP: 2 \"a\" \"b\"\r\n",
- "acc-name: Buchi\r\n",
- "Acceptance: 1 Inf(0)\r\n",
- "properties: trans-labels explicit-labels state-acc deterministic\r\n",
- "properties: stutter-invariant terminal\r\n",
- "--BODY--\r\n",
- "State: 0 {0}\r\n",
- "[t] 0\r\n",
- "State: 1\r\n",
- "[1] 0\r\n",
- "[0&!1] 1\r\n",
- "--END--\r\n",
- "2 1\r\n",
- "0 1 -1\r\n",
- "1 \"b\"\r\n",
- "0 & \"a\" ! \"b\"\r\n",
- "-1\r\n",
- "1 0 0 -1\r\n",
- "1 t\r\n",
- "-1\r\n"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for a in spot.automata('example.aut'):\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201e09c0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201ff1b0> >"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Test `--ABORT--`\n",
- "----------------"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "%%file example.aut\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 1\n",
- "AP: 2 \"a\" \"b\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 1 Inf(0)\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0\n",
- "--ABORT-- /* the previous automaton should be ignored */\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 1\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Inf(0)\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0\n",
- "State: 1\n",
- "[1] 0\n",
- "[0&!1] 1\n",
- "--END--"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "Overwriting example.aut\n"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for a in spot.automata('example.aut'):\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201e0900> >"
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for a in spot.automata(\"\"\"\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 1\n",
- "name: \"Hello world\"\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Inf(0)\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0\n",
- "State: 1\n",
- "[1] 0\n",
- "[0&!1] 1\n",
- "--END--\n",
- "HOA: v1\n",
- "States: 1\n",
- "Start: 0\n",
- "name: \"Hello world 2\"\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 2 Inf(0)&Inf(1)\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0 {1}\n",
- "[0&!1] 0\n",
- "--END--\n",
- "\"\"\"):\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201ff1b0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201e0900> >"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Test syntax errors\n",
- "------------------"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "%%file example.aut\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 1\n",
- "AP: 2 \"a\" \"b\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 1 Inf(0)\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 1\n",
- "State: 1\n",
- "[t] 1\n",
- "--END--\n",
- "HOA: v1\n",
- "States: 2\n",
- "Start: 1\n",
- "AP: 2 \"a\" \"b\"\n",
- "Acceptance: 1 Inf(0)\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[a] 3\n",
- "State: 1\n",
- "[1] 0\n",
- "[0&!1] 1\n",
- "--END--"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "Overwriting example.aut\n"
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for a in spot.automata('example.aut'):\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201ff390> >"
- ]
- },
- {
- "ename": "SyntaxError",
- "evalue": "\nexample.aut:20.2: syntax error, unexpected identifier\nexample.aut:20.1-3: ignoring this invalid label\nexample.aut:20.5: state number is larger than state count...\nexample.aut:14.1-9: ... declared here.\n ()",
- "output_type": "pyerr",
- "traceback": [
- "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32munknown\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m \nexample.aut:20.2: syntax error, unexpected identifier\nexample.aut:20.1-3: ignoring this invalid label\nexample.aut:20.5: state number is larger than state count...\nexample.aut:14.1-9: ... declared here.\n\n"
- ]
- }
- ],
- "prompt_number": 10
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('example.aut', timeout=100)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 11,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7f45201ff270> >"
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.automaton('non-existing-cmd |')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "ename": "CalledProcessError",
- "evalue": "Command 'non-existing-cmd ' returned non-zero exit status 127",
- "output_type": "pyerr",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'non-existing-cmd |'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 471\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 472\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 473\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 474\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 475\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, ignore_abort, trust_hoa, debug, *sources)\u001b[0m\n\u001b[1;32m 456\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 457\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 458\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 459\u001b[0m \u001b[0;31m# deleting o explicitely now prevents Python 3.5 from\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 460\u001b[0m \u001b[0;31m# reporting the following error: \"\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sleep 3; cat example.aut |'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 471\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 472\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 473\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 474\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 475\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/home/adl/git/spot/python/spot/__init__.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, ignore_abort, trust_hoa, debug, *sources)\u001b[0m\n\u001b[1;32m 415\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 416\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 417\u001b[0;31m \u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0merr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcommunicate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 418\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTimeoutExpired\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 419\u001b[0m \u001b[0;31m# Using subprocess.check_output() with timeout\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/usr/lib/python3.5/subprocess.py\u001b[0m in \u001b[0;36mcommunicate\u001b[0;34m(self, input, timeout)\u001b[0m\n\u001b[1;32m 1063\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1064\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1065\u001b[0;31m \u001b[0mstdout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstderr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_communicate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mendtime\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1066\u001b[0m \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1067\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_communication_started\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/usr/lib/python3.5/subprocess.py\u001b[0m in \u001b[0;36m_communicate\u001b[0;34m(self, input, endtime, orig_timeout)\u001b[0m\n\u001b[1;32m 1698\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1699\u001b[0m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mselector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1700\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_check_timeout\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mendtime\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morig_timeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1701\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1702\u001b[0m \u001b[0;31m# XXX Rewrite these to use non-blocking I/O on the file\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/usr/lib/python3.5/subprocess.py\u001b[0m in \u001b[0;36m_check_timeout\u001b[0;34m(self, endtime, orig_timeout)\u001b[0m\n\u001b[1;32m 1089\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1090\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m_time\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0mendtime\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1091\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTimeoutExpired\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0morig_timeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1092\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1093\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mTimeoutExpired\u001b[0m: Command 'sleep 3; cat example.aut ' timed out after 1 seconds"
- ]
- }
- ],
- "prompt_number": 13
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "rm example.aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 14
- }
- ],
- "metadata": {}
+ "version": "3.6.4"
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/automata.ipynb b/tests/python/automata.ipynb
index 89272b53a..3ab2d982a 100644
--- a/tests/python/automata.ipynb
+++ b/tests/python/automata.ipynb
@@ -1,4 +1,3637 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "from IPython.display import display\n",
+ "import spot\n",
+ "spot.setup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To build an automaton, 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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1043b73f0> >"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = spot.translate('(a U b) & GFc & GFd', 'BA', '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 explicitely. For instance here is a vertical layout with the default font of GraphViz."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.show(\".ast\")"
+ ]
+ },
+ {
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$a \\mathbin{\\mathsf{U}} b$"
+ ],
+ "text/plain": [
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042bc900> >"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.translate(f)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce7b0> >"
+ ]
+ },
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1043b7390> >"
+ ]
+ },
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} a \\lor \\mathsf{G} b \\lor \\mathsf{G} c$"
+ ],
+ "text/plain": [
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f.translate('ba', 'small').show('.v')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "f.translate('ba', 'det').show('v.')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here is how to build an unambiguous automaton:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce870> >"
+ ]
+ },
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042bc660> >"
+ ]
+ },
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce6c0> >"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.translate('GFa -> GFb', 'sbacc')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Some example of running the self-loopization algorithm on an automaton:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1043dd600> >"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a = spot.translate('F(a & X(!a &Xb))', \"any\"); a"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce600> >"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.sl(a)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 17,
+ "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": 18,
+ "metadata": {
+ "collapsed": false
+ },
+ "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: 4 Inf(0)&Fin(1)&Fin(3) | Inf(2)&Inf(3) | Inf(1)\n",
+ "--BODY--\n",
+ "State: 0 {3}\n",
+ "[t] 0\n",
+ "[0] 1 {1}\n",
+ "[!0] 2 {0}\n",
+ "State: 1 {3}\n",
+ "[1] 0\n",
+ "[0&1] 1 {0}\n",
+ "[!0&1] 2 {2}\n",
+ "State: 2\n",
+ "[!1] 0\n",
+ "[0&!1] 1 {0}\n",
+ "[!0&!1] 2 {0}\n",
+ "--END--"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042bc8d0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "a = spot.automaton('example1.aut')\n",
+ "display(a.show('.a'))\n",
+ "display(spot.remove_fin(a).show('.a'))\n",
+ "display(a.postprocess('TGBA', 'complete').show('.a'))\n",
+ "display(a.postprocess('BA'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "!rm example1.aut"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce780> >"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.complete(a)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce8a0> >"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.complete(spot.translate('Ga'))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Using +1 in the display options is a convient way to shift the \n",
+ "# set numbers in the output, as an aid in reading the product.\n",
+ "a1 = spot.translate('a W c'); display(a1.show('.bat'))\n",
+ "a2 = spot.translate('a U b'); display(a2.show('.bat+1'))\n",
+ "# the product should display pairs of states, unless asked not to (using 1).\n",
+ "p = spot.product(a1, a2); display(p.show('.bat')); display(p.show('.bat1'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Explicit determinization after translation:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce810> >"
+ ]
+ },
+ "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": 25,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.tgba_determinize(a).show('.ba')"
+ ]
+ },
+ {
+ "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": 26,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce7e0> >"
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.translate('FGa', 'generic', 'deterministic'); aut"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Adding an atomic proposition to all edges"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce7e0> >"
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import buddy\n",
+ "b = buddy.bdd_ithvar(aut.register_ap('b'))\n",
+ "for e in aut.edges():\n",
+ " e.cond &= b\n",
+ "aut"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Adding an atomic proposition to the edge between 0 and 1:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fb1042ce7e0> >"
+ ]
+ },
+ "execution_count": 28,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "c = buddy.bdd_ithvar(aut.register_ap('c'))\n",
+ "for e in aut.out(0):\n",
+ " if e.dst == 1:\n",
+ " e.cond &= c\n",
+ "aut"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,3583 +3649,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "from IPython.display import display\n",
- "import spot\n",
- "spot.setup()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To build an automaton, 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",
- "collapsed": false,
- "input": [
- "a = spot.translate('(a U b) & GFc & GFd', 'BA', 'complete'); a"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1043b73f0> >"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "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 explicitely. For instance here is a vertical layout with the default font of GraphViz."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.show(\"v\")"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "a.show(\".ast\")"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "f = spot.formula('a U b'); f"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$a \\mathbin{\\mathsf{U}} b$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "text": [
- "a U b"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.translate(f)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042bc900> >"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f.translate()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 7,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce7b0> >"
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When used as a method, all the arguments are translation options. Here is a monitor:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f.translate('mon')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 8,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1043b7390> >"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "f = spot.formula('Ga | Gb | Gc'); f"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$\\mathsf{G} a \\lor \\mathsf{G} b \\lor \\mathsf{G} c$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 9,
- "text": [
- "Ga | Gb | Gc"
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f.translate('ba', 'small').show('.v')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 10,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 10
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f.translate('ba', 'det').show('v.')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 11,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Here is how to build an unambiguous automaton:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.translate('GFa -> GFb', 'unambig')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 12,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce870> >"
- ]
- }
- ],
- "prompt_number": 12
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Compare with the standard translation:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.translate('GFa -> GFb')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 13,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042bc660> >"
- ]
- }
- ],
- "prompt_number": 13
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "And here is the automaton above with state-based acceptance:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.translate('GFa -> GFb', 'sbacc')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 14,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce6c0> >"
- ]
- }
- ],
- "prompt_number": 14
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Some example of running the self-loopization algorithm on an automaton:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.translate('F(a & X(!a &Xb))', \"any\"); a"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 15,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1043dd600> >"
- ]
- }
- ],
- "prompt_number": 15
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.sl(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 16,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce600> >"
- ]
- }
- ],
- "prompt_number": 16
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.is_empty()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 17,
- "text": [
- "False"
- ]
- }
- ],
- "prompt_number": 17
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Reading from file (see `automaton-io.ipynb` for more examples)."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "%%file example1.aut\n",
- "HOA: v1\n",
- "States: 3\n",
- "Start: 0\n",
- "AP: 2 \"a\" \"b\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 4 Inf(0)&Fin(1)&Fin(3) | Inf(2)&Inf(3) | Inf(1)\n",
- "--BODY--\n",
- "State: 0 {3}\n",
- "[t] 0\n",
- "[0] 1 {1}\n",
- "[!0] 2 {0}\n",
- "State: 1 {3}\n",
- "[1] 0\n",
- "[0&1] 1 {0}\n",
- "[!0&1] 2 {2}\n",
- "State: 2\n",
- "[!1] 0\n",
- "[0&!1] 1 {0}\n",
- "[!0&!1] 2 {0}\n",
- "--END--"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "Writing example1.aut\n"
- ]
- }
- ],
- "prompt_number": 18
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.automaton('example1.aut')\n",
- "display(a.show('.a'))\n",
- "display(spot.remove_fin(a).show('.a'))\n",
- "display(a.postprocess('TGBA', 'complete').show('.a'))\n",
- "display(a.postprocess('BA'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042bc8d0> >"
- ]
- }
- ],
- "prompt_number": 19
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "!rm example1.aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 20
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.complete(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 21,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce780> >"
- ]
- }
- ],
- "prompt_number": 21
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.complete(spot.translate('Ga'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 22,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce8a0> >"
- ]
- }
- ],
- "prompt_number": 22
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "# Using +1 in the display options is a convient way to shift the \n",
- "# set numbers in the output, as an aid in reading the product.\n",
- "a1 = spot.translate('a W c'); display(a1.show('.bat'))\n",
- "a2 = spot.translate('a U b'); display(a2.show('.bat+1'))\n",
- "# the product should display pairs of states, unless asked not to (using 1).\n",
- "p = spot.product(a1, a2); display(p.show('.bat')); display(p.show('.bat1'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 23
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Explicit determinization after translation:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.translate('FGa')\n",
- "display(a)\n",
- "display(a.is_deterministic())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce810> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "False"
- ]
- }
- ],
- "prompt_number": 24
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.tgba_determinize(a).show('.ba')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 25,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 25
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Determinization by `translate()`. The `generic` option allows any acceptance condition to be used instead of the default generalized B\u00fcchi."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.translate('FGa', 'generic', 'deterministic'); aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 26,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce7e0> >"
- ]
- }
- ],
- "prompt_number": 26
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Adding an atomic proposition to all edges"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "import buddy\n",
- "b = buddy.bdd_ithvar(aut.register_ap('b'))\n",
- "for e in aut.edges():\n",
- " e.cond &= b\n",
- "aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 27,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce7e0> >"
- ]
- }
- ],
- "prompt_number": 27
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Adding an atomic proposition to the edge between 0 and 1:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "c = buddy.bdd_ithvar(aut.register_ap('c'))\n",
- "for e in aut.out(0):\n",
- " if e.dst == 1:\n",
- " e.cond &= c\n",
- "aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 28,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fb1042ce7e0> >"
- ]
- }
- ],
- "prompt_number": 28
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/decompose.ipynb b/tests/python/decompose.ipynb
index c6c99f630..80a1ecb84 100644
--- a/tests/python/decompose.ipynb
+++ b/tests/python/decompose.ipynb
@@ -1,4 +1,5454 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": true
+ },
+ "outputs": [],
+ "source": [
+ "from IPython.display import display\n",
+ "import spot\n",
+ "spot.setup(show_default='.bans')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook demonstrates how to use the `decompose_scc()` function to split an automaton in up to three automata capturing different behaviors. This is based on the paper [Strength-based decomposition of the property Büchi automaton for faster model checking](https://www.lrde.epita.fr/~adl/dl/adl/renault.13.tacas.pdf) (TACAS'13).\n",
+ "\n",
+ "This page uses the Python bindings, but the same decompositions can be performed from the shell using [`autfilt`](https://spot.lrde.epita.fr/autfilt.html) and its `--decompose-scc` option.\n",
+ "\n",
+ "# Basics\n",
+ "\n",
+ "Let's define the following strengths of accepting SCCs:\n",
+ "\n",
+ "- an accepting SCC is **inherently weak** if it does not contain any rejecting cycle\n",
+ "- an accepting SCC is **inherently terminal** if it is *inherently weak* and complete (i.e. from any state, you can stay in the SCC by reading any word)\n",
+ "- an accepting SCC is **strictly inherently weak** if it is *inherently weak* and not complete (in other words: *weak* but not *terminal*)\n",
+ "- an accepting SCC is **strong** if it is not inherently weak.\n",
+ "\n",
+ "The strengths **strong**, **stricly inherently weak**, and **inherently terminal** define a partition of all accepting SCCs. The following Büchi automaton has 4 SCCs, and its 3 accepting SCCs show an example of each strength.\n",
+ "\n",
+ "Note: the reason we use the word *inherently* is that the *weak* and *terminal* properties are usually defined syntactically: an accepting SCC would be weak if all its transitions belong to the same acceptance sets. This syntactic criterion is a sufficient condition for an accepting SCC to not have any rejecting cycle, but it is not necessary. Hence a *weak* SCC is *inherently weak*; but while an *inherently weak* SCC is not necessarily *weak*, it can be modified to be *weak* without alterning the langage."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc5466510> >"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.translate('(Ga -> Gb) W c')\n",
+ "aut"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `decompose_strength()` function takes an automaton, and a string specifying which strength to preserve. \n",
+ "\n",
+ "The letters used for this specification are as follows:\n",
+ "\n",
+ "- `t`: (inherently) terminal\n",
+ "- `w`: (strictly inherently) weak\n",
+ "- `s`: strong\n",
+ "\n",
+ "For instance if we want to preserve only the **strictly inherently weak** part of this automaton, we should get only the SCC with the self-loop on $b$, and the SCC above it so that we can reach it. However the SCC above is not stricly weak, so it should not accept any word in the new automaton."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca420> >"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.decompose_scc(aut, 'w')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Similarly, we can extract all the behaviors captured by the **inherently terminal** part of the automaton:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca1b0> >"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.decompose_scc(aut, 't')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here is the **strong** part:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc5466330> >"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "strong = spot.decompose_scc(aut, 's'); strong"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The union of these three automata recognize the same language as the original automaton.\n",
+ "\n",
+ "\n",
+ "The application proposed in the aforementioned TACAS'13 paper is for parallelizing model checking. Instead of testing the emptiness of the product between `aut` and a system, one could test the emptiness **3** products in parallel: each with a sub-automaton of different strength. Model checking using weak and terminal automata can be done with much more simpler emptiness check procedures than needed for the general case. So in effect, we have isolated the \"hard\" (i.e. strong) part of the original automaton in a smaller automaton, and we only need to use a full-fledged emptiness check for this case.\n",
+ "\n",
+ "An additional bonus is that it is possible that the simplification algorithms will do a better job at simplifying the sub-automata than at simplifying the original `aut`. For instance here the `strong` automaton can be further simplified:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca180> >"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "strong.postprocess('small')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Multi-strength extraction\n",
+ "\n",
+ "The string passed to `decompose_strength()` can include multiple letters to extract multiple strengths at once."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca360> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca120> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca390> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for opt in ('sw', 'st', 'wt'):\n",
+ " a = spot.decompose_scc(aut, opt)\n",
+ " a.set_name(\"option: \" + opt)\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Generalized acceptance\n",
+ "\n",
+ "There is nothing that prevents the above decomposition to work with other types of acceptance.\n",
+ "\n",
+ "## Rabin\n",
+ "\n",
+ "The following Rabin automaton was generated with\n",
+ "\n",
+ " ltldo -f '(Ga -> Gb) W c' 'ltl2dstar --ltl2nba=spin:ltl2tgba@-Ds' -H | autfilt -H --merge-transitions\n",
+ " \n",
+ "(The `autfilt -H --merge-transitions` pass is just here to reduce the size of the file and make the automaton more readable.)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec1e0> >"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.automaton(\"\"\"\n",
+ "HOA: v1\n",
+ "States: 9\n",
+ "Start: 2\n",
+ "AP: 3 \"a\" \"b\" \"c\"\n",
+ "acc-name: Rabin 2\n",
+ "Acceptance: 4 (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
+ "properties: trans-labels explicit-labels state-acc complete\n",
+ "properties: deterministic\n",
+ "--BODY--\n",
+ "State: 0 {2}\n",
+ "[0&!2] 0\n",
+ "[0&2] 1\n",
+ "[!0&!2] 5\n",
+ "[!0&2] 6\n",
+ "State: 1 {2}\n",
+ "[0] 1\n",
+ "[!0] 6\n",
+ "State: 2 {2}\n",
+ "[0&!1&!2] 3\n",
+ "[0&1&!2] 4\n",
+ "[!0&!2] 5\n",
+ "[2] 6\n",
+ "State: 3 {1 2}\n",
+ "[0&!2] 0\n",
+ "[0&2] 1\n",
+ "[!0&!2] 5\n",
+ "[!0&2] 6\n",
+ "State: 4 {1 2}\n",
+ "[0&!1&!2] 0\n",
+ "[0&!1&2] 1\n",
+ "[!0&!2] 5\n",
+ "[!0&2] 6\n",
+ "[0&1&!2] 7\n",
+ "[0&1&2] 8\n",
+ "State: 5 {1 2}\n",
+ "[0&!1&!2] 0\n",
+ "[!0&!2] 5\n",
+ "[2] 6\n",
+ "[0&1&!2] 7\n",
+ "State: 6 {1 2}\n",
+ "[t] 6\n",
+ "State: 7 {3}\n",
+ "[0&!1&!2] 0\n",
+ "[0&!1&2] 1\n",
+ "[!0&!2] 5\n",
+ "[!0&2] 6\n",
+ "[0&1&!2] 7\n",
+ "[0&1&2] 8\n",
+ "State: 8 {3}\n",
+ "[0&!1] 1\n",
+ "[!0] 6\n",
+ "[0&1] 8\n",
+ "--END--\n",
+ "\"\"\")\n",
+ "aut"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's decompose it into three strengths:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca450> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca360> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bcac30> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for (name, opt) in (('terminal', 't'), ('strictly weak', 'w'), ('strong', 's')):\n",
+ " a = spot.decompose_scc(aut, opt)\n",
+ " a.set_name(name)\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note how the two weak automata (i.e., stricly weak and terminal) are now using a Büchi acceptance condition (because that is sufficient for weak automata) while the strong automaton inherited the original acceptance condition.\n",
+ "\n",
+ "When extracting multiple strengths and one of the strength is **strong**, we preserve the original acceptance. For instance extracting **strong** and **inherently terminal** gives the following automaton, where only **stricly inherently weak** SCCs have become rejecting."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc5466300> >"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.decompose_scc(aut, \"st\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The weak automata seem to be good candidates for further simplification. Let's add a call to `postprocess()` to out decomposition loop, trying to preserve the determinism and state-based acceptance of the original automaton."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bcac90> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca270> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca120> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for (name, opt) in (('inherently terminal', 't'), ('strictly inherently weak', 'w'), ('strong', 's')):\n",
+ " a = spot.decompose_scc(aut, opt).postprocess('deterministic', 'SBAcc')\n",
+ " a.set_name(name)\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Streett\n",
+ "\n",
+ "Since this notebook also serves as a test suite, let's try a Streett automaton. This one was generated with\n",
+ "\n",
+ " ltldo -f '(Ga -> Gb) W c' 'ltl2dstar --automata=streett --ltl2nba=spin:ltl2tgba@-Ds' -H | \n",
+ " autfilt -H --merge-transitions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec2d0> >"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.automaton(\"\"\"\n",
+ "HOA: v1\n",
+ "States: 8\n",
+ "Start: 7\n",
+ "AP: 3 \"a\" \"b\" \"c\"\n",
+ "acc-name: Streett 2\n",
+ "Acceptance: 4 (Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n",
+ "properties: trans-labels explicit-labels state-acc complete\n",
+ "properties: deterministic\n",
+ "--BODY--\n",
+ "State: 0 {2}\n",
+ "[0&1] 0\n",
+ "[0&!1] 3\n",
+ "[!0] 4\n",
+ "State: 1 {2}\n",
+ "[0&1&2] 0\n",
+ "[0&1&!2] 1\n",
+ "[0&!1&!2] 2\n",
+ "[0&!1&2] 3\n",
+ "[!0&2] 4\n",
+ "[!0&!2] 7\n",
+ "State: 2 {2}\n",
+ "[0&1&!2] 1\n",
+ "[0&!1&!2] 2\n",
+ "[0&2] 3\n",
+ "[!0&2] 4\n",
+ "[!0&!2] 7\n",
+ "State: 3 {0 3}\n",
+ "[0] 3\n",
+ "[!0] 4\n",
+ "State: 4 {1 3}\n",
+ "[t] 4\n",
+ "State: 5 {3}\n",
+ "[0&!1] 3\n",
+ "[!0] 4\n",
+ "[0&1] 5\n",
+ "State: 6 {3}\n",
+ "[0&!1&!2] 2\n",
+ "[0&!1&2] 3\n",
+ "[!0&2] 4\n",
+ "[0&1&2] 5\n",
+ "[0&1&!2] 6\n",
+ "[!0&!2] 7\n",
+ "State: 7 {3}\n",
+ "[0&!1&!2] 2\n",
+ "[2] 4\n",
+ "[0&1&!2] 6\n",
+ "[!0&!2] 7\n",
+ "--END--\n",
+ "\"\"\")\n",
+ "aut"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bcac30> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca330> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca120> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for (name, opt) in (('inherently terminal', 't'), ('strictly inherently weak', 'w'), ('strong', 's')):\n",
+ " a = spot.decompose_strength(aut, opt)\n",
+ " a.set_name(name)\n",
+ " display(a)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The subtlety of Streett acceptance is that if a path that does not visit any accepting set infinitely often *is* accepting. So when disabling SCCs, we must be careful to label them with a combination of rejecting acceptance sets.\n",
+ "\n",
+ "This is easy to understand using an example. In the following extraction of the **strong** and **inherently terminal** parts, the rejecting SCCs (that were either rejecting or strictly inherently weak originally) have been labeled by the same acceptance sets, to ensure that they are rejected."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec540> >"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.decompose_scc(aut, 'st')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Corner cases\n",
+ "\n",
+ "When the acceptance condition is always satisfiable, all non-trivial SCCs are accepting, and inherently weak.\n",
+ "\n",
+ "This include acceptances like `Acceptance: 0 t`, but also trickier ones like `Acceptance: 1 Inf(0) | Fin(0)` that you can make as complex as you fancy.\n",
+ "\n",
+ "### `Acceptance: 0 t`\n",
+ "\n",
+ "This occur frequently whant translating LTL formulas that are safety properties:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca270> >"
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.translate('(Gb|c) R a', 'any'); aut"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "# There is no strong part for this automaton\n",
+ "assert spot.decompose_scc(aut, 's') is None"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bcac30> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bcac30> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for opt in ('w', 't'):\n",
+ " display(spot.decompose_scc(aut, opt))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we try to extract multiple strengths and include the (empty) strong part, this request will simply be ignored:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec870> >"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.decompose_scc(aut, 'st')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that the above is exactly the output of `decompose_strength(aut, 't')`. The `'s'` flag was actively ignored. If `'s'` had not been ignored an the automaton processed as if its strong part had to be preserved, the original acceptance conditions would have been used, and this would have prevented the disabling of the initial SCC."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### `Acceptance: 1 Inf(0) | Fin(0)`\n",
+ "\n",
+ "This acceptance could be replaced by `Acceptance: 0 t` without altering the language of the automaton. However its use of acceptance sets allows us to define some automata with SCCs that are *inherently weak* but not *weak*."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec270> >"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.automaton(\"\"\"\n",
+ "HOA: v1\n",
+ "States: 4\n",
+ "Start: 0\n",
+ "AP: 1 \"a\"\n",
+ "Acceptance: 1 Inf(0) | Fin(0)\n",
+ "--BODY--\n",
+ "State: 0\n",
+ "[0] 0 \n",
+ "[!0] 1\n",
+ "State: 1\n",
+ "[0] 1 \n",
+ "[!0] 2 {0}\n",
+ "State: 2\n",
+ "[0] 1\n",
+ "[!0] 3\n",
+ "State: 3\n",
+ "[t] 3 {0}\n",
+ "--END--\n",
+ "\"\"\")\n",
+ "aut"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "By our definitions, SCC $\\{0\\}$ and $\\{1,2\\}$ are inherently weak, and SCC $\\{3\\}$ is terminal."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bca2d0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec630> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "no output for strong\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec930> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for (name, opt) in (('terminal', 't'), ('strictly weak', 'w'), ('strong', 's'), ('all strengths', 'swt')):\n",
+ " a = spot.decompose_scc(aut, opt)\n",
+ " if a:\n",
+ " a.set_name(name)\n",
+ " display(a)\n",
+ " else:\n",
+ " print(\"no output for \" + name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "collapsed": false
+ },
+ "source": [
+ "# `decompose_scc()` by SCC number\n",
+ "\n",
+ "Decompose SCC can also be called by SCC numbers.\n",
+ "The example below show the different SCC numbers and the state they contains, before extracting the sub-automaton containing SCC 1 and 2 (i.e., anything leading to states 1 and 4 of the original automaton). This example also shows that when an `scc_info` is available for to automaton to decompose, it can be passed to `decompose_scc()` in lieu of the automaton: doing so is faster because `decompose_scc()` does not need to rebuild this object. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "SCC #0 containts states [1]\n",
+ "SCC #1 containts states [2]\n",
+ "SCC #2 containts states [4]\n",
+ "SCC #3 containts states [0, 3]\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4b87210> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec7b0> >"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.translate('(Ga -> Gb) W c')\n",
+ "si = spot.scc_info(aut)\n",
+ "for scc in range(si.scc_count()):\n",
+ " print(\"SCC #{} containts states {}\".format(scc, list(si.states_of(scc))))\n",
+ "display(aut)\n",
+ "spot.decompose_scc(si, '1,2')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If an SCC number N is prefixed by `a`, it signifies that we want to extract the Nth *accepting* SCC. In the above example SCC 2 is rejecting so SCC `a2` denotes SCC 3."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7effc4bec180> >"
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.decompose_scc(si, 'a2')"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,5400 +5466,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": true,
- "input": [
- "from IPython.display import display\n",
- "import spot\n",
- "spot.setup(show_default='.bans')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This notebook demonstrates how to use the `decompose_scc()` function to split an automaton in up to three automata capturing different behaviors. This is based on the paper [Strength-based decomposition of the property B\u00fcchi automaton for faster model checking](https://www.lrde.epita.fr/~adl/dl/adl/renault.13.tacas.pdf) (TACAS'13).\n",
- "\n",
- "This page uses the Python bindings, but the same decompositions can be performed from the shell using [`autfilt`](https://spot.lrde.epita.fr/autfilt.html) and its `--decompose-scc` option.\n",
- "\n",
- "# Basics\n",
- "\n",
- "Let's define the following strengths of accepting SCCs:\n",
- "\n",
- "- an accepting SCC is **inherently weak** if it does not contain any rejecting cycle\n",
- "- an accepting SCC is **inherently terminal** if it is *inherently weak* and complete (i.e. from any state, you can stay in the SCC by reading any word)\n",
- "- an accepting SCC is **strictly inherently weak** if it is *inherently weak* and not complete (in other words: *weak* but not *terminal*)\n",
- "- an accepting SCC is **strong** if it is not inherently weak.\n",
- "\n",
- "The strengths **strong**, **stricly inherently weak**, and **inherently terminal** define a partition of all accepting SCCs. The following B\u00fcchi automaton has 4 SCCs, and its 3 accepting SCCs show an example of each strength.\n",
- "\n",
- "Note: the reason we use the word *inherently* is that the *weak* and *terminal* properties are usually defined syntactically: an accepting SCC would be weak if all its transitions belong to the same acceptance sets. This syntactic criterion is a sufficient condition for an accepting SCC to not have any rejecting cycle, but it is not necessary. Hence a *weak* SCC is *inherently weak*; but while an *inherently weak* SCC is not necessarily *weak*, it can be modified to be *weak* without alterning the langage."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.translate('(Ga -> Gb) W c')\n",
- "aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc5466510> >"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `decompose_strength()` function takes an automaton, and a string specifying which strength to preserve. \n",
- "\n",
- "The letters used for this specification are as follows:\n",
- "\n",
- "- `t`: (inherently) terminal\n",
- "- `w`: (strictly inherently) weak\n",
- "- `s`: strong\n",
- "\n",
- "For instance if we want to preserve only the **strictly inherently weak** part of this automaton, we should get only the SCC with the self-loop on $b$, and the SCC above it so that we can reach it. However the SCC above is not stricly weak, so it should not accept any word in the new automaton."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.decompose_scc(aut, 'w')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca420> >"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Similarly, we can extract all the behaviors captured by the **inherently terminal** part of the automaton:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.decompose_scc(aut, 't')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca1b0> >"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Here is the **strong** part:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "strong = spot.decompose_scc(aut, 's'); strong"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc5466330> >"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The union of these three automata recognize the same language as the original automaton.\n",
- "\n",
- "\n",
- "The application proposed in the aforementioned TACAS'13 paper is for parallelizing model checking. Instead of testing the emptiness of the product between `aut` and a system, one could test the emptiness **3** products in parallel: each with a sub-automaton of different strength. Model checking using weak and terminal automata can be done with much more simpler emptiness check procedures than needed for the general case. So in effect, we have isolated the \"hard\" (i.e. strong) part of the original automaton in a smaller automaton, and we only need to use a full-fledged emptiness check for this case.\n",
- "\n",
- "An additional bonus is that it is possible that the simplification algorithms will do a better job at simplifying the sub-automata than at simplifying the original `aut`. For instance here the `strong` automaton can be further simplified:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "strong.postprocess('small')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca180> >"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Multi-strength extraction\n",
- "\n",
- "The string passed to `decompose_strength()` can include multiple letters to extract multiple strengths at once."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for opt in ('sw', 'st', 'wt'):\n",
- " a = spot.decompose_scc(aut, opt)\n",
- " a.set_name(\"option: \" + opt)\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca360> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca120> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca390> >"
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Generalized acceptance\n",
- "\n",
- "There is nothing that prevents the above decomposition to work with other types of acceptance.\n",
- "\n",
- "## Rabin\n",
- "\n",
- "The following Rabin automaton was generated with\n",
- "\n",
- " ltldo -f '(Ga -> Gb) W c' 'ltl2dstar --ltl2nba=spin:ltl2tgba@-Ds' -H | autfilt -H --merge-transitions\n",
- " \n",
- "(The `autfilt -H --merge-transitions` pass is just here to reduce the size of the file and make the automaton more readable.)"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.automaton(\"\"\"\n",
- "HOA: v1\n",
- "States: 9\n",
- "Start: 2\n",
- "AP: 3 \"a\" \"b\" \"c\"\n",
- "acc-name: Rabin 2\n",
- "Acceptance: 4 (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
- "properties: trans-labels explicit-labels state-acc complete\n",
- "properties: deterministic\n",
- "--BODY--\n",
- "State: 0 {2}\n",
- "[0&!2] 0\n",
- "[0&2] 1\n",
- "[!0&!2] 5\n",
- "[!0&2] 6\n",
- "State: 1 {2}\n",
- "[0] 1\n",
- "[!0] 6\n",
- "State: 2 {2}\n",
- "[0&!1&!2] 3\n",
- "[0&1&!2] 4\n",
- "[!0&!2] 5\n",
- "[2] 6\n",
- "State: 3 {1 2}\n",
- "[0&!2] 0\n",
- "[0&2] 1\n",
- "[!0&!2] 5\n",
- "[!0&2] 6\n",
- "State: 4 {1 2}\n",
- "[0&!1&!2] 0\n",
- "[0&!1&2] 1\n",
- "[!0&!2] 5\n",
- "[!0&2] 6\n",
- "[0&1&!2] 7\n",
- "[0&1&2] 8\n",
- "State: 5 {1 2}\n",
- "[0&!1&!2] 0\n",
- "[!0&!2] 5\n",
- "[2] 6\n",
- "[0&1&!2] 7\n",
- "State: 6 {1 2}\n",
- "[t] 6\n",
- "State: 7 {3}\n",
- "[0&!1&!2] 0\n",
- "[0&!1&2] 1\n",
- "[!0&!2] 5\n",
- "[!0&2] 6\n",
- "[0&1&!2] 7\n",
- "[0&1&2] 8\n",
- "State: 8 {3}\n",
- "[0&!1] 1\n",
- "[!0] 6\n",
- "[0&1] 8\n",
- "--END--\n",
- "\"\"\")\n",
- "aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 8,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec1e0> >"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Let's decompose it into three strengths:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for (name, opt) in (('terminal', 't'), ('strictly weak', 'w'), ('strong', 's')):\n",
- " a = spot.decompose_scc(aut, opt)\n",
- " a.set_name(name)\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca450> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca360> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bcac30> >"
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Note how the two weak automata (i.e., stricly weak and terminal) are now using a B\u00fcchi acceptance condition (because that is sufficient for weak automata) while the strong automaton inherited the original acceptance condition.\n",
- "\n",
- "When extracting multiple strengths and one of the strength is **strong**, we preserve the original acceptance. For instance extracting **strong** and **inherently terminal** gives the following automaton, where only **stricly inherently weak** SCCs have become rejecting."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.decompose_scc(aut, \"st\")"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 10,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc5466300> >"
- ]
- }
- ],
- "prompt_number": 10
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The weak automata seem to be good candidates for further simplification. Let's add a call to `postprocess()` to out decomposition loop, trying to preserve the determinism and state-based acceptance of the original automaton."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for (name, opt) in (('inherently terminal', 't'), ('strictly inherently weak', 'w'), ('strong', 's')):\n",
- " a = spot.decompose_scc(aut, opt).postprocess('deterministic', 'SBAcc')\n",
- " a.set_name(name)\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bcac90> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca270> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca120> >"
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Streett\n",
- "\n",
- "Since this notebook also serves as a test suite, let's try a Streett automaton. This one was generated with\n",
- "\n",
- " ltldo -f '(Ga -> Gb) W c' 'ltl2dstar --automata=streett --ltl2nba=spin:ltl2tgba@-Ds' -H | \n",
- " autfilt -H --merge-transitions"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.automaton(\"\"\"\n",
- "HOA: v1\n",
- "States: 8\n",
- "Start: 7\n",
- "AP: 3 \"a\" \"b\" \"c\"\n",
- "acc-name: Streett 2\n",
- "Acceptance: 4 (Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n",
- "properties: trans-labels explicit-labels state-acc complete\n",
- "properties: deterministic\n",
- "--BODY--\n",
- "State: 0 {2}\n",
- "[0&1] 0\n",
- "[0&!1] 3\n",
- "[!0] 4\n",
- "State: 1 {2}\n",
- "[0&1&2] 0\n",
- "[0&1&!2] 1\n",
- "[0&!1&!2] 2\n",
- "[0&!1&2] 3\n",
- "[!0&2] 4\n",
- "[!0&!2] 7\n",
- "State: 2 {2}\n",
- "[0&1&!2] 1\n",
- "[0&!1&!2] 2\n",
- "[0&2] 3\n",
- "[!0&2] 4\n",
- "[!0&!2] 7\n",
- "State: 3 {0 3}\n",
- "[0] 3\n",
- "[!0] 4\n",
- "State: 4 {1 3}\n",
- "[t] 4\n",
- "State: 5 {3}\n",
- "[0&!1] 3\n",
- "[!0] 4\n",
- "[0&1] 5\n",
- "State: 6 {3}\n",
- "[0&!1&!2] 2\n",
- "[0&!1&2] 3\n",
- "[!0&2] 4\n",
- "[0&1&2] 5\n",
- "[0&1&!2] 6\n",
- "[!0&!2] 7\n",
- "State: 7 {3}\n",
- "[0&!1&!2] 2\n",
- "[2] 4\n",
- "[0&1&!2] 6\n",
- "[!0&!2] 7\n",
- "--END--\n",
- "\"\"\")\n",
- "aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 12,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec2d0> >"
- ]
- }
- ],
- "prompt_number": 12
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for (name, opt) in (('inherently terminal', 't'), ('strictly inherently weak', 'w'), ('strong', 's')):\n",
- " a = spot.decompose_strength(aut, opt)\n",
- " a.set_name(name)\n",
- " display(a)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bcac30> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca330> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca120> >"
- ]
- }
- ],
- "prompt_number": 13
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The subtlety of Streett acceptance is that if a path that does not visit any accepting set infinitely often *is* accepting. So when disabling SCCs, we must be careful to label them with a combination of rejecting acceptance sets.\n",
- "\n",
- "This is easy to understand using an example. In the following extraction of the **strong** and **inherently terminal** parts, the rejecting SCCs (that were either rejecting or strictly inherently weak originally) have been labeled by the same acceptance sets, to ensure that they are rejected."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.decompose_scc(aut, 'st')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 14,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec540> >"
- ]
- }
- ],
- "prompt_number": 14
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Corner cases\n",
- "\n",
- "When the acceptance condition is always satisfiable, all non-trivial SCCs are accepting, and inherently weak.\n",
- "\n",
- "This include acceptances like `Acceptance: 0 t`, but also trickier ones like `Acceptance: 1 Inf(0) | Fin(0)` that you can make as complex as you fancy.\n",
- "\n",
- "### `Acceptance: 0 t`\n",
- "\n",
- "This occur frequently whant translating LTL formulas that are safety properties:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.translate('(Gb|c) R a', 'any'); aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 15,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca270> >"
- ]
- }
- ],
- "prompt_number": 15
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "# There is no strong part for this automaton\n",
- "assert spot.decompose_scc(aut, 's') is None"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 16
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for opt in ('w', 't'):\n",
- " display(spot.decompose_scc(aut, opt))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bcac30> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bcac30> >"
- ]
- }
- ],
- "prompt_number": 17
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If we try to extract multiple strengths and include the (empty) strong part, this request will simply be ignored:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.decompose_scc(aut, 'st')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 18,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec870> >"
- ]
- }
- ],
- "prompt_number": 18
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Note that the above is exactly the output of `decompose_strength(aut, 't')`. The `'s'` flag was actively ignored. If `'s'` had not been ignored an the automaton processed as if its strong part had to be preserved, the original acceptance conditions would have been used, and this would have prevented the disabling of the initial SCC."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### `Acceptance: 1 Inf(0) | Fin(0)`\n",
- "\n",
- "This acceptance could be replaced by `Acceptance: 0 t` without altering the language of the automaton. However its use of acceptance sets allows us to define some automata with SCCs that are *inherently weak* but not *weak*."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.automaton(\"\"\"\n",
- "HOA: v1\n",
- "States: 4\n",
- "Start: 0\n",
- "AP: 1 \"a\"\n",
- "Acceptance: 1 Inf(0) | Fin(0)\n",
- "--BODY--\n",
- "State: 0\n",
- "[0] 0 \n",
- "[!0] 1\n",
- "State: 1\n",
- "[0] 1 \n",
- "[!0] 2 {0}\n",
- "State: 2\n",
- "[0] 1\n",
- "[!0] 3\n",
- "State: 3\n",
- "[t] 3 {0}\n",
- "--END--\n",
- "\"\"\")\n",
- "aut"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 19,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec270> >"
- ]
- }
- ],
- "prompt_number": 19
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "By our definitions, SCC $\\{0\\}$ and $\\{1,2\\}$ are inherently weak, and SCC $\\{3\\}$ is terminal."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for (name, opt) in (('terminal', 't'), ('strictly weak', 'w'), ('strong', 's'), ('all strengths', 'swt')):\n",
- " a = spot.decompose_scc(aut, opt)\n",
- " if a:\n",
- " a.set_name(name)\n",
- " display(a)\n",
- " else:\n",
- " print(\"no output for \" + name)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bca2d0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec630> >"
- ]
- },
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "no output for strong\n"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec930> >"
- ]
- }
- ],
- "prompt_number": 20
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "collapsed": false
- },
- "source": [
- "# `decompose_scc()` by SCC number\n",
- "\n",
- "Decompose SCC can also be called by SCC numbers.\n",
- "The example below show the different SCC numbers and the state they contains, before extracting the sub-automaton containing SCC 1 and 2 (i.e., anything leading to states 1 and 4 of the original automaton). This example also shows that when an `scc_info` is available for to automaton to decompose, it can be passed to `decompose_scc()` in lieu of the automaton: doing so is faster because `decompose_scc()` does not need to rebuild this object. "
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "aut = spot.translate('(Ga -> Gb) W c')\n",
- "si = spot.scc_info(aut)\n",
- "for scc in range(si.scc_count()):\n",
- " print(\"SCC #{} containts states {}\".format(scc, list(si.states_of(scc))))\n",
- "display(aut)\n",
- "spot.decompose_scc(si, '1,2')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "SCC #0 containts states [1]\n",
- "SCC #1 containts states [2]\n",
- "SCC #2 containts states [4]\n",
- "SCC #3 containts states [0, 3]\n"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4b87210> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 21,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec7b0> >"
- ]
- }
- ],
- "prompt_number": 21
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If an SCC number N is prefixed by `a`, it signifies that we want to extract the Nth *accepting* SCC. In the above example SCC 2 is rejecting so SCC `a2` denotes SCC 3."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.decompose_scc(si, 'a2')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 22,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7effc4bec180> >"
- ]
- }
- ],
- "prompt_number": 22
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/formulas.ipynb b/tests/python/formulas.ipynb
index 4786cfd19..4f20ffc1f 100644
--- a/tests/python/formulas.ipynb
+++ b/tests/python/formulas.ipynb
@@ -1,4 +1,887 @@
{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Handling LTL and PSL formulas\n",
+ "============================="
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{a;b[*];c[+]}<>-> GFb\n"
+ ]
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "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": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "g.show_mp_hierarchy()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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": {
+ "collapsed": false
+ },
+ "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",
@@ -16,857 +899,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Handling LTL and PSL formulas\n",
- "============================="
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "import spot"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "f = spot.formula('p1 U p2 R (p3 & !p4)')\n",
- "f"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "text": [
- "p1 U (p2 R (p3 & !p4))"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "g = spot.formula('{a;b*;c[+]}<>->GFb'); g"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$\\{a \\mathbin{\\mathsf{;}} b^{\\star} \\mathbin{\\mathsf{;}} c^+\\}\\mathrel{\\Diamond\\kern-1.7pt\\raise.4pt\\hbox{$\\mathord{\\rightarrow}$}} \\mathsf{G} \\mathsf{F} b$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "text": [
- "{a;b[*];c[+]}<>-> GFb"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "h = spot.formula('& | a b c'); h"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$c \\land (a \\lor b)$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "text": [
- "c & (a | b)"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Passing a `formula` to `spot.formula` simply returns the formula."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.formula(h)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$c \\land (a \\lor b)$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "text": [
- "c & (a | b)"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "str(f)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "text": [
- "'p1 U (p2 R (p3 & !p4))'"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "for i in ['spot', 'spin', 'lbt', 'wring', 'utf8', 'latex', 'sclatex']:\n",
- " print(\"%-10s%s\" % (i, f.to_str(i)))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "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\u2227\u00acp4))\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"
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Formulas output via `format()` can also use some convenient shorthand to select the syntax:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "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))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "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"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The specifiers that can be used with `format` are documented as follows:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "help(spot.formula.__format__)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "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"
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "f.is_in_nenoform() and f.is_ltl_formula()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 10,
- "text": [
- "True"
- ]
- }
- ],
- "prompt_number": 10
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "g.is_ltl_formula()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 11,
- "text": [
- "False"
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "f.is_syntactic_stutter_invariant()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 12,
- "text": [
- "True"
- ]
- }
- ],
- "prompt_number": 12
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.formula('{a[*];b}<>->c').is_syntactic_stutter_invariant()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 13,
- "text": [
- "False"
- ]
- }
- ],
- "prompt_number": 13
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.formula('{a[+];b[*]}<>->d').is_syntactic_stutter_invariant()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 14,
- "text": [
- "True"
- ]
- }
- ],
- "prompt_number": 14
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "gf = spot.formula('(GF_foo_) && \"a > b\" && \"proc[2]@init\"'); gf"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$``\\mathit{a > b}\\textrm{''} \\land ``\\mathit{proc[2]@init}\\textrm{''} \\land \\mathsf{G} \\mathsf{F} \\mathit{\\_foo\\_}$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 15,
- "text": [
- "\"a > b\" & \"proc[2]@init\" & GF_foo_"
- ]
- }
- ],
- "prompt_number": 15
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.relabel(gf, spot.Abc)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$a \\land b \\land \\mathsf{G} \\mathsf{F} c$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 16,
- "text": [
- "a & b & GFc"
- ]
- }
- ],
- "prompt_number": 16
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.relabel(gf, spot.Pnn)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$p_{0} \\land p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2}$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 17,
- "text": [
- "p0 & p1 & GFp2"
- ]
- }
- ],
- "prompt_number": 17
- },
- {
- "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",
- "collapsed": false,
- "input": [
- "print(g); g.show_ast()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "{a;b[*];c[+]}<>-> GFb\n"
- ]
- },
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 18,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 18
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Any formula can also be classified in the temporal hierarchy of Manna & Pnueli"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "g.show_mp_hierarchy()"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 19,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 19
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.mp_class(g, 'v')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 20,
- "text": [
- "'recurrence'"
- ]
- }
- ],
- "prompt_number": 20
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f = spot.formula('F(a & X(!a & b))'); f"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$\\mathsf{F} (a \\land \\mathsf{X} (\\lnot a \\land b))$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 21,
- "text": [
- "F(a & X(!a & b))"
- ]
- }
- ],
- "prompt_number": 21
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Etessami's rule for removing X (valid only in stutter-invariant formulas)"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.remove_x(f)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "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))))$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 22,
- "text": [
- "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))))"
- ]
- }
- ],
- "prompt_number": 22
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Removing abbreviated operators"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "f = spot.formula(\"G(a xor b) -> F(a <-> b)\")\n",
- "spot.unabbreviate(f, \"GF^\")"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$(\\bot \\mathbin{\\mathsf{R}} \\lnot (a \\leftrightarrow b)) \\rightarrow (\\top \\mathbin{\\mathsf{U}} (a \\leftrightarrow b))$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 23,
- "text": [
- "(0 R !(a <-> b)) -> (1 U (a <-> b))"
- ]
- }
- ],
- "prompt_number": 23
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.unabbreviate(f, \"GF^ei\")"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "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)))$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 24,
- "text": [
- "(1 U ((a & b) | (!a & !b))) | !(0 R ((!a & b) | (a & !b)))"
- ]
- }
- ],
- "prompt_number": 24
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Nesting level of operators"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "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\"))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "U 3\n",
- "F 2\n",
- "U 3\n",
- "F 2\n",
- "FU 4\n"
- ]
- }
- ],
- "prompt_number": 25
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/gen.ipynb b/tests/python/gen.ipynb
index 78af79137..b313e1bdc 100644
--- a/tests/python/gen.ipynb
+++ b/tests/python/gen.ipynb
@@ -1,4 +1,935 @@
{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Formulas & Automata generators\n",
+ "\n",
+ "The `spot.gen` package contains the functions used to generate the patterns produced by [`genltl`](https://spot.lrde.epita.fr/genltl.html) and [`genaut`](https://spot.lrde.epita.fr/genaut.html)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "import spot.gen as sg\n",
+ "spot.setup()\n",
+ "from IPython.display import display"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## LTL patterns\n",
+ "\n",
+ "Generation of LTL formulas is done via the `ltl_pattern()` function. This takes two arguments: a pattern id, and a pattern size (or index if the id refers to a list)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} \\mathsf{F} p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2} \\land \\mathsf{G} \\mathsf{F} p_{3}$"
+ ],
+ "text/plain": [
+ "GFp1 & GFp2 & GFp3"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sg.ltl_pattern(sg.LTL_AND_GF, 3)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} (p \\land \\mathsf{X} p \\land \\mathsf{X} \\mathsf{X} p \\land \\mathsf{X} \\mathsf{X} \\mathsf{X} p) \\land \\mathsf{F} (q \\land \\mathsf{X} q \\land \\mathsf{X} \\mathsf{X} q \\land \\mathsf{X} \\mathsf{X} \\mathsf{X} q)$"
+ ],
+ "text/plain": [
+ "F(p & Xp & XXp & XXXp) & F(q & Xq & XXq & XXXq)"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "sg.ltl_pattern(sg.LTL_CCJ_BETA_PRIME, 4)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To see the list of supported patterns, the easiest way is to look at the `--help` output of `genltl`. The above pattern for instance is attached to option `--ccj-beta-prime`. The name of the pattern identifier is the same using capital letters, underscores, and an `LTL_` prefix. If a pattern has multiple aliased options in `genltl`, the first one used for the identifier (e.g., `genltl` accept both `--dac-patterns` and `--spec-patterns` as synonyms to denote the patterns of `spot.gen.LTL_DAC_PATTERNS`).\n",
+ "\n",
+ "Multiple patterns can be generated using the `ltl_patterns()` function. It's arguments should be either can be:\n",
+ " - pairs of the form `(id, n)`: in this case the pattern `id` with size/index `n` is returned,\n",
+ " - triplets of the form `(id, min, max)`: in this case the patterns are output for all `n` between `min` and `max` included,\n",
+ " - an integer `id`: then this is equivalent to `(id, 1, 10)` if the pattern has now upper bound, or `(id, 1, upper)` if the patter `id` has an upper bound `upper`. This is mostly used when the pattern id correspond to a hard-coded list of formulas.\n",
+ "\n",
+ "Here is an example showing these three types of arguments:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false,
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$(\\mathsf{G} \\mathsf{F} p_{1} \\lor \\mathsf{F} \\mathsf{G} p_{2}) \\land (\\mathsf{G} \\mathsf{F} p_{2} \\lor \\mathsf{F} \\mathsf{G} p_{3}) \\land (\\mathsf{G} \\mathsf{F} p_{3} \\lor \\mathsf{F} \\mathsf{G} p_{4})$"
+ ],
+ "text/plain": [
+ "(GFp1 | FGp2) & (GFp2 | FGp3) & (GFp3 | FGp4)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} \\mathsf{G} p_{1}$"
+ ],
+ "text/plain": [
+ "FGp1"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} \\mathsf{G} p_{1} \\land \\mathsf{F} \\mathsf{G} p_{2}$"
+ ],
+ "text/plain": [
+ "FGp1 & FGp2"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} \\mathsf{G} p_{1} \\land \\mathsf{F} \\mathsf{G} p_{2} \\land \\mathsf{F} \\mathsf{G} p_{3}$"
+ ],
+ "text/plain": [
+ "FGp1 & FGp2 & FGp3"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\land \\mathsf{G} p_{2})$"
+ ],
+ "text/plain": [
+ "p0 U (p1 & Gp2)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\land \\mathsf{X} (p_{2} \\mathbin{\\mathsf{U}} p_{3}))$"
+ ],
+ "text/plain": [
+ "p0 U (p1 & X(p2 U p3))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\land \\mathsf{X} (p_{2} \\land \\mathsf{F} (p_{3} \\land \\mathsf{X} \\mathsf{F} (p_{4} \\land \\mathsf{X} \\mathsf{F} (p_{5} \\land \\mathsf{X} \\mathsf{F} p_{6})))))$"
+ ],
+ "text/plain": [
+ "p0 U (p1 & X(p2 & F(p3 & XF(p4 & XF(p5 & XFp6)))))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} (p_{0} \\land \\mathsf{X} \\mathsf{G} p_{1})$"
+ ],
+ "text/plain": [
+ "F(p0 & XGp1)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} (p_{0} \\land \\mathsf{X} (p_{1} \\land \\mathsf{X} \\mathsf{F} p_{2}))$"
+ ],
+ "text/plain": [
+ "F(p0 & X(p1 & XFp2))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{F} (p_{0} \\land \\mathsf{X} (p_{1} \\mathbin{\\mathsf{U}} p_{2}))$"
+ ],
+ "text/plain": [
+ "F(p0 & X(p1 U p2))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} \\mathsf{F} p_{0} \\lor \\mathsf{F} \\mathsf{G} p_{1}$"
+ ],
+ "text/plain": [
+ "GFp0 | FGp1"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} (p_{0} \\rightarrow (p_{1} \\mathbin{\\mathsf{U}} p_{2}))$"
+ ],
+ "text/plain": [
+ "G(p0 -> (p1 U p2))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} (p_{0} \\land \\mathsf{X} \\mathsf{F} (p_{1} \\land \\mathsf{X} \\mathsf{F} (p_{2} \\land \\mathsf{X} \\mathsf{F} p_{3})))$"
+ ],
+ "text/plain": [
+ "G(p0 & XF(p1 & XF(p2 & XFp3)))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} \\mathsf{F} p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2} \\land \\mathsf{G} \\mathsf{F} p_{3} \\land \\mathsf{G} \\mathsf{F} p_{0} \\land \\mathsf{G} \\mathsf{F} p_{4}$"
+ ],
+ "text/plain": [
+ "GFp1 & GFp2 & GFp3 & GFp0 & GFp4"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$(p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\mathbin{\\mathsf{U}} p_{2})) \\lor (p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{U}} p_{0})) \\lor (p_{2} \\mathbin{\\mathsf{U}} (p_{0} \\mathbin{\\mathsf{U}} p_{1}))$"
+ ],
+ "text/plain": [
+ "(p0 U (p1 U p2)) | (p1 U (p2 U p0)) | (p2 U (p0 U p1))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/latex": [
+ "$\\mathsf{G} (p_{0} \\rightarrow (p_{1} \\mathbin{\\mathsf{U}} (\\mathsf{G} p_{2} \\lor \\mathsf{G} p_{3})))$"
+ ],
+ "text/plain": [
+ "G(p0 -> (p1 U (Gp2 | Gp3)))"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for f in sg.ltl_patterns((sg.LTL_GH_R, 3), (sg.LTL_AND_FG, 1, 3), sg.LTL_EH_PATTERNS):\n",
+ " display(f)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Automata patterns\n",
+ "\n",
+ "We currently have only a couple of generators of automata:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(sg.aut_pattern(sg.AUT_KS_NCA, 3).show('.a'),\n",
+ " sg.aut_pattern(sg.AUT_L_DSA, 3).show('.a'),\n",
+ " sg.aut_pattern(sg.AUT_L_NBA, 3).show('.a'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Multiple automata can be generated using the `aut_patterns()` function, which works similarly to `ltl_patterns()`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3\n",
+ "5\n",
+ "7\n",
+ "9\n",
+ "11\n",
+ "13\n",
+ "15\n",
+ "17\n",
+ "19\n",
+ "21\n"
+ ]
+ }
+ ],
+ "source": [
+ "for aut in sg.aut_patterns(sg.AUT_KS_NCA):\n",
+ " print(aut.num_states())"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,904 +947,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Formulas & Automata generators\n",
- "\n",
- "The `spot.gen` package contains the functions used to generate the patterns produced by [`genltl`](https://spot.lrde.epita.fr/genltl.html) and [`genaut`](https://spot.lrde.epita.fr/genaut.html)."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "import spot\n",
- "import spot.gen as sg\n",
- "spot.setup()\n",
- "from IPython.display import display"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## LTL patterns\n",
- "\n",
- "Generation of LTL formulas is done via the `ltl_pattern()` function. This takes two arguments: a pattern id, and a pattern size (or index if the id refers to a list)."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "sg.ltl_pattern(sg.LTL_AND_GF, 3)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$\\mathsf{G} \\mathsf{F} p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2} \\land \\mathsf{G} \\mathsf{F} p_{3}$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 2,
- "text": [
- "GFp1 & GFp2 & GFp3"
- ]
- }
- ],
- "prompt_number": 2
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "sg.ltl_pattern(sg.LTL_CCJ_BETA_PRIME, 4)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "latex": [
- "$\\mathsf{F} (p \\land \\mathsf{X} p \\land \\mathsf{X} \\mathsf{X} p \\land \\mathsf{X} \\mathsf{X} \\mathsf{X} p) \\land \\mathsf{F} (q \\land \\mathsf{X} q \\land \\mathsf{X} \\mathsf{X} q \\land \\mathsf{X} \\mathsf{X} \\mathsf{X} q)$"
- ],
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "text": [
- "F(p & Xp & XXp & XXXp) & F(q & Xq & XXq & XXXq)"
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To see the list of supported patterns, the easiest way is to look at the `--help` output of `genltl`. The above pattern for instance is attached to option `--ccj-beta-prime`. The name of the pattern identifier is the same using capital letters, underscores, and an `LTL_` prefix. If a pattern has multiple aliased options in `genltl`, the first one used for the identifier (e.g., `genltl` accept both `--dac-patterns` and `--spec-patterns` as synonyms to denote the patterns of `spot.gen.LTL_DAC_PATTERNS`).\n",
- "\n",
- "Multiple patterns can be generated using the `ltl_patterns()` function. It's arguments should be either can be:\n",
- " - pairs of the form `(id, n)`: in this case the pattern `id` with size/index `n` is returned,\n",
- " - triplets of the form `(id, min, max)`: in this case the patterns are output for all `n` between `min` and `max` included,\n",
- " - an integer `id`: then this is equivalent to `(id, 1, 10)` if the pattern has now upper bound, or `(id, 1, upper)` if the patter `id` has an upper bound `upper`. This is mostly used when the pattern id correspond to a hard-coded list of formulas.\n",
- "\n",
- "Here is an example showing these three types of arguments:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for f in sg.ltl_patterns((sg.LTL_GH_R, 3), (sg.LTL_AND_FG, 1, 3), sg.LTL_EH_PATTERNS):\n",
- " display(f)"
- ],
- "language": "python",
- "metadata": {
- "scrolled": false
- },
- "outputs": [
- {
- "latex": [
- "$(\\mathsf{G} \\mathsf{F} p_{1} \\lor \\mathsf{F} \\mathsf{G} p_{2}) \\land (\\mathsf{G} \\mathsf{F} p_{2} \\lor \\mathsf{F} \\mathsf{G} p_{3}) \\land (\\mathsf{G} \\mathsf{F} p_{3} \\lor \\mathsf{F} \\mathsf{G} p_{4})$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "(GFp1 | FGp2) & (GFp2 | FGp3) & (GFp3 | FGp4)"
- ]
- },
- {
- "latex": [
- "$\\mathsf{F} \\mathsf{G} p_{1}$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "FGp1"
- ]
- },
- {
- "latex": [
- "$\\mathsf{F} \\mathsf{G} p_{1} \\land \\mathsf{F} \\mathsf{G} p_{2}$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "FGp1 & FGp2"
- ]
- },
- {
- "latex": [
- "$\\mathsf{F} \\mathsf{G} p_{1} \\land \\mathsf{F} \\mathsf{G} p_{2} \\land \\mathsf{F} \\mathsf{G} p_{3}$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "FGp1 & FGp2 & FGp3"
- ]
- },
- {
- "latex": [
- "$p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\land \\mathsf{G} p_{2})$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "p0 U (p1 & Gp2)"
- ]
- },
- {
- "latex": [
- "$p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\land \\mathsf{X} (p_{2} \\mathbin{\\mathsf{U}} p_{3}))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "p0 U (p1 & X(p2 U p3))"
- ]
- },
- {
- "latex": [
- "$p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\land \\mathsf{X} (p_{2} \\land \\mathsf{F} (p_{3} \\land \\mathsf{X} \\mathsf{F} (p_{4} \\land \\mathsf{X} \\mathsf{F} (p_{5} \\land \\mathsf{X} \\mathsf{F} p_{6})))))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "p0 U (p1 & X(p2 & F(p3 & XF(p4 & XF(p5 & XFp6)))))"
- ]
- },
- {
- "latex": [
- "$\\mathsf{F} (p_{0} \\land \\mathsf{X} \\mathsf{G} p_{1})$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "F(p0 & XGp1)"
- ]
- },
- {
- "latex": [
- "$\\mathsf{F} (p_{0} \\land \\mathsf{X} (p_{1} \\land \\mathsf{X} \\mathsf{F} p_{2}))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "F(p0 & X(p1 & XFp2))"
- ]
- },
- {
- "latex": [
- "$\\mathsf{F} (p_{0} \\land \\mathsf{X} (p_{1} \\mathbin{\\mathsf{U}} p_{2}))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "F(p0 & X(p1 U p2))"
- ]
- },
- {
- "latex": [
- "$\\mathsf{G} \\mathsf{F} p_{0} \\lor \\mathsf{F} \\mathsf{G} p_{1}$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "GFp0 | FGp1"
- ]
- },
- {
- "latex": [
- "$\\mathsf{G} (p_{0} \\rightarrow (p_{1} \\mathbin{\\mathsf{U}} p_{2}))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "G(p0 -> (p1 U p2))"
- ]
- },
- {
- "latex": [
- "$\\mathsf{G} (p_{0} \\land \\mathsf{X} \\mathsf{F} (p_{1} \\land \\mathsf{X} \\mathsf{F} (p_{2} \\land \\mathsf{X} \\mathsf{F} p_{3})))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "G(p0 & XF(p1 & XF(p2 & XFp3)))"
- ]
- },
- {
- "latex": [
- "$\\mathsf{G} \\mathsf{F} p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2} \\land \\mathsf{G} \\mathsf{F} p_{3} \\land \\mathsf{G} \\mathsf{F} p_{0} \\land \\mathsf{G} \\mathsf{F} p_{4}$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "GFp1 & GFp2 & GFp3 & GFp0 & GFp4"
- ]
- },
- {
- "latex": [
- "$(p_{0} \\mathbin{\\mathsf{U}} (p_{1} \\mathbin{\\mathsf{U}} p_{2})) \\lor (p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{U}} p_{0})) \\lor (p_{2} \\mathbin{\\mathsf{U}} (p_{0} \\mathbin{\\mathsf{U}} p_{1}))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "(p0 U (p1 U p2)) | (p1 U (p2 U p0)) | (p2 U (p0 U p1))"
- ]
- },
- {
- "latex": [
- "$\\mathsf{G} (p_{0} \\rightarrow (p_{1} \\mathbin{\\mathsf{U}} (\\mathsf{G} p_{2} \\lor \\mathsf{G} p_{3})))$"
- ],
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "G(p0 -> (p1 U (Gp2 | Gp3)))"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Automata patterns\n",
- "\n",
- "We currently have only a couple of generators of automata:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "display(sg.aut_pattern(sg.AUT_KS_NCA, 3).show('.a'),\n",
- " sg.aut_pattern(sg.AUT_L_DSA, 3).show('.a'),\n",
- " sg.aut_pattern(sg.AUT_L_NBA, 3).show('.a'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Multiple automata can be generated using the `aut_patterns()` function, which works similarly to `ltl_patterns()`."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "for aut in sg.aut_patterns(sg.AUT_KS_NCA):\n",
- " print(aut.num_states())"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "3\n",
- "5\n",
- "7\n",
- "9\n",
- "11\n",
- "13\n",
- "15\n",
- "17\n",
- "19\n",
- "21\n"
- ]
- }
- ],
- "prompt_number": 6
- }
- ],
- "metadata": {}
}
- ]
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
}
diff --git a/tests/python/highlighting.ipynb b/tests/python/highlighting.ipynb
index 1d89b59e7..c7247503a 100644
--- a/tests/python/highlighting.ipynb
+++ b/tests/python/highlighting.ipynb
@@ -1,4 +1,2514 @@
{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import spot\n",
+ "spot.setup()\n",
+ "from IPython.display import display"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook shows you different ways in which states or transitions can be highlighted in Spot. \n",
+ "\n",
+ "It should be noted that highlighting works using some special [named properties](https://spot.lrde.epita.fr/concepts.html#named-properties): basically, two maps that are attached to the automaton, and associated state or edge numbers to color numbers. This named properties are fragile: they will be lost if the automaton is transformed into a new automaton, and they can become meaningless of the automaton is modified in place (e.g., if the transitions or states are reordered).\n",
+ "\n",
+ "Nonetheless, highlighting is OK to use right before displaying or printing the automaton. The `dot` and `hoa` printer both know how to represent highlighted states and transitions.\n",
+ "\n",
+ "# Manual highlighting"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "a = spot.translate('a U b U c')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The `#` option of `print_dot()` can be used to display the internal number of each transition "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.show('.#')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Using these numbers you can selectively hightlight some transitions. The second argument is a color number (from a list of predefined colors)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe1205e8990> >"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.highlight_edges([2, 4, 5], 1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note that these `highlight_` functions work for edges and states, and come with both singular (changing the color of single state or edge) and plural versions.\n",
+ "\n",
+ "They modify the automaton in place."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe1205e8a80> >"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.highlight_edge(6, 2).highlight_states((0, 1), 0)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The plural version can take a list or tuple of state numbers (as above) or of Booleans (as below). In the latter case the indices of the True values give the states to highlight."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe1205e8990> >"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "a.highlight_states([False, True, True], 5)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Saving to HOA 1.1\n",
+ "\n",
+ "When saving to HOA format, the highlighting is only output if version 1.1 of the format is selected, because the headers `spot.highlight.edges` and `spot.highlight.states` contain dots, which are disallowed in version 1. Compare these two outputs:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "HOA: v1\n",
+ "States: 3\n",
+ "Start: 2\n",
+ "AP: 3 \"a\" \"b\" \"c\"\n",
+ "acc-name: Buchi\n",
+ "Acceptance: 1 Inf(0)\n",
+ "properties: trans-labels explicit-labels state-acc deterministic\n",
+ "properties: stutter-invariant terminal\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0\n",
+ "State: 1\n",
+ "[2] 0\n",
+ "[1&!2] 1\n",
+ "State: 2\n",
+ "[2] 0\n",
+ "[!0&1&!2] 1\n",
+ "[0&!2] 2\n",
+ "--END--\n",
+ "\n",
+ "HOA: v1.1\n",
+ "States: 3\n",
+ "Start: 2\n",
+ "AP: 3 \"a\" \"b\" \"c\"\n",
+ "acc-name: Buchi\n",
+ "Acceptance: 1 Inf(0)\n",
+ "properties: trans-labels explicit-labels state-acc !complete\n",
+ "properties: deterministic stutter-invariant terminal\n",
+ "spot.highlight.states: 0 0 1 5 2 5\n",
+ "spot.highlight.edges: 2 1 4 1 5 1 6 2\n",
+ "--BODY--\n",
+ "State: 0 {0}\n",
+ "[t] 0\n",
+ "State: 1\n",
+ "[2] 0\n",
+ "[1&!2] 1\n",
+ "State: 2\n",
+ "[2] 0\n",
+ "[!0&1&!2] 1\n",
+ "[0&!2] 2\n",
+ "--END--\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(a.to_str('HOA', '1'))\n",
+ "print()\n",
+ "print(a.to_str('HOA', '1.1'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Highlighting a run\n",
+ "\n",
+ "One use of this highlighting is to highlight a run in an automaton.\n",
+ "\n",
+ "The following few command generate an automaton, then an accepting run on this automaton, and highlight that accepting run on the automaton. Note that a run knows the automaton from which it was generated, so calling `highlight()` will directly decorate that automaton."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d1b0> >"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "b = spot.translate('X (F(Ga <-> b) & GF!b)'); b"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Prefix:\n",
+ " 0\n",
+ " | 1\n",
+ " 1\n",
+ " | !a & !b\n",
+ "Cycle:\n",
+ " 2\n",
+ " | !b\t{0}"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "r = b.accepting_run(); r"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "r.highlight(5) # the parameter is a color number"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The call of `highlight(5)` on the accepting run `r` modified the original automaton `b`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d1b0> >"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Highlighting from a product\n",
+ "\n",
+ "Pretty often, accepting runs are found in a product but we want to display them on one of the original automata. This can be done by projecting the runs on those automata before displaying them."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d2d0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d150> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "left = spot.translate('a U b')\n",
+ "right = spot.translate('GFa')\n",
+ "display(left, right)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d2a0> >"
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "prod = spot.product(left, right); prod"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Prefix:\n",
+ " 1,0\n",
+ " | !a & b\n",
+ "Cycle:\n",
+ " 0,0\n",
+ " | !a\t{0}\n",
+ " 0,0\n",
+ " | a\t{0,1}"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "run = prod.accepting_run(); run"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "run.highlight(5)\n",
+ "# Note that by default project() needs to know on which side you project, but it cannot \n",
+ "# guess it. The left-side is assumed unless you pass True as a second argument.\n",
+ "run.project(left).highlight(5)\n",
+ "run.project(right, True).highlight(5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d2a0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d2d0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d150> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(prod, left, right)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The projection also works for products generated on-the-fly, but the on-the-fly product itself cannot be highlighted (it does not store states or transitions). "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Prefix:\n",
+ " 0 * 3\n",
+ " | a & !b\n",
+ " 1 * 2\n",
+ " | a\t{0}\n",
+ " 1 * 1\n",
+ " | a\t{0}\n",
+ " 1 * 0\n",
+ " | a & b\t{0}\n",
+ "Cycle:\n",
+ " 1 * 4\n",
+ " | a\t{0,1}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d210> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d1e0> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d270> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "left2 = spot.translate('!b & FG a')\n",
+ "right2 = spot.translate('XXXb')\n",
+ "prod2 = spot.otf_product(left2, right2) # Note \"otf_product()\"\n",
+ "run2 = prod2.accepting_run()\n",
+ "run2.project(left2).highlight(5)\n",
+ "run2.project(right2, True).highlight(5)\n",
+ "display(run2, prod2, left2, right2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Highlighting nondeterminism\n",
+ "\n",
+ "Sometimes its is hard to locate non-deterministic states inside a large automaton. Here are two functions that can help for that."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d330> >"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "b = spot.translate('X (F(Ga <-> b) & GF!b)')\n",
+ "spot.highlight_nondet_states(b, 5)\n",
+ "spot.highlight_nondet_edges(b, 4)\n",
+ "b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Disappearing highlights\n",
+ "\n",
+ "As explained at the top of this notebook, named properties (such as highlights) are fragile, and you should not really on them being preserved across algorithms. In-place algorithm are probably the worst, because they might modify the automaton and ignore the attached named properties. \n",
+ "\n",
+ "`randomize()` is one such in-place algorithm: it reorder states or transitions of the automaton. By doing so it renumber the states and edges, and that process would completely invalidate the highlights information. Fortunately `randomize()` know about highlights: it will preserve highlighted states, but it will drop all highlighted edges."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d330> >"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "spot.randomize(b); b"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Highlighting with partial output\n",
+ "\n",
+ "For simplicity, rendering of partial automata is actually implemented by copying the original automaton and marking some states as \"incomplete\". This also allows the same display code to work with automata generated on-the-fly. However since there is a copy, propagating the highlighting information requires extra work. Let's make sure it has been done:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ " *' at 0x7fe12058d330> >"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "spot.highlight_nondet_edges(b, 4) # let's get those highlighted edges back\n",
+ "display(b, b.show('.<4'), b.show('.<2'))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Highlighting languages\n",
+ "\n",
+ "For deterministic automata, the function `spot.highlight_languages()` can be used to highlight states that recognize the same language. This can be a great help in reading automata. States with a colored border share their language, and states with a black border all have a language different from all other states."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "aut = spot.translate('(b W Xa) & GF(c <-> Xb) | a', 'generic', 'det')\n",
+ "spot.highlight_languages(aut)\n",
+ "aut.show('.bas')"
+ ]
+ }
+ ],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
@@ -16,2476 +2526,8 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
- },
- "name": ""
- },
- "nbformat": 3,
- "nbformat_minor": 0,
- "worksheets": [
- {
- "cells": [
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "import spot\n",
- "spot.setup()\n",
- "from IPython.display import display"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 1
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This notebook shows you different ways in which states or transitions can be highlighted in Spot. \n",
- "\n",
- "It should be noted that highlighting works using some special [named properties](https://spot.lrde.epita.fr/concepts.html#named-properties): basically, two maps that are attached to the automaton, and associated state or edge numbers to color numbers. This named properties are fragile: they will be lost if the automaton is transformed into a new automaton, and they can become meaningless of the automaton is modified in place (e.g., if the transitions or states are reordered).\n",
- "\n",
- "Nonetheless, highlighting is OK to use right before displaying or printing the automaton. The `dot` and `hoa` printer both know how to represent highlighted states and transitions.\n",
- "\n",
- "# Manual highlighting"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a = spot.translate('a U b U c')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 2
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `#` option of `print_dot()` can be used to display the internal number of each transition "
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.show('.#')"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 3,
- "svg": [
- ""
- ],
- "text": [
- ""
- ]
- }
- ],
- "prompt_number": 3
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Using these numbers you can selectively hightlight some transitions. The second argument is a color number (from a list of predefined colors)."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.highlight_edges([2, 4, 5], 1)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 4,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe1205e8990> >"
- ]
- }
- ],
- "prompt_number": 4
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Note that these `highlight_` functions work for edges and states, and come with both singular (changing the color of single state or edge) and plural versions.\n",
- "\n",
- "They modify the automaton in place."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.highlight_edge(6, 2).highlight_states((0, 1), 0)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 5,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe1205e8a80> >"
- ]
- }
- ],
- "prompt_number": 5
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The plural version can take a list or tuple of state numbers (as above) or of Booleans (as below). In the latter case the indices of the True values give the states to highlight."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "a.highlight_states([False, True, True], 5)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 6,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe1205e8990> >"
- ]
- }
- ],
- "prompt_number": 6
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Saving to HOA 1.1\n",
- "\n",
- "When saving to HOA format, the highlighting is only output if version 1.1 of the format is selected, because the headers `spot.highlight.edges` and `spot.highlight.states` contain dots, which are disallowed in version 1. Compare these two outputs:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "print(a.to_str('HOA', '1'))\n",
- "print()\n",
- "print(a.to_str('HOA', '1.1'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "output_type": "stream",
- "stream": "stdout",
- "text": [
- "HOA: v1\n",
- "States: 3\n",
- "Start: 2\n",
- "AP: 3 \"a\" \"b\" \"c\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 1 Inf(0)\n",
- "properties: trans-labels explicit-labels state-acc deterministic\n",
- "properties: stutter-invariant terminal\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0\n",
- "State: 1\n",
- "[2] 0\n",
- "[1&!2] 1\n",
- "State: 2\n",
- "[2] 0\n",
- "[!0&1&!2] 1\n",
- "[0&!2] 2\n",
- "--END--\n",
- "\n",
- "HOA: v1.1\n",
- "States: 3\n",
- "Start: 2\n",
- "AP: 3 \"a\" \"b\" \"c\"\n",
- "acc-name: Buchi\n",
- "Acceptance: 1 Inf(0)\n",
- "properties: trans-labels explicit-labels state-acc !complete\n",
- "properties: deterministic stutter-invariant terminal\n",
- "spot.highlight.states: 0 0 1 5 2 5\n",
- "spot.highlight.edges: 2 1 4 1 5 1 6 2\n",
- "--BODY--\n",
- "State: 0 {0}\n",
- "[t] 0\n",
- "State: 1\n",
- "[2] 0\n",
- "[1&!2] 1\n",
- "State: 2\n",
- "[2] 0\n",
- "[!0&1&!2] 1\n",
- "[0&!2] 2\n",
- "--END--\n"
- ]
- }
- ],
- "prompt_number": 7
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Highlighting a run\n",
- "\n",
- "One use of this highlighting is to highlight a run in an automaton.\n",
- "\n",
- "The following few command generate an automaton, then an accepting run on this automaton, and highlight that accepting run on the automaton. Note that a run knows the automaton from which it was generated, so calling `highlight()` will directly decorate that automaton."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "b = spot.translate('X (F(Ga <-> b) & GF!b)'); b"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 8,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d1b0> >"
- ]
- }
- ],
- "prompt_number": 8
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "r = b.accepting_run(); r"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 9,
- "text": [
- "Prefix:\n",
- " 0\n",
- " | 1\n",
- " 1\n",
- " | !a & !b\n",
- "Cycle:\n",
- " 2\n",
- " | !b\t{0}"
- ]
- }
- ],
- "prompt_number": 9
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "r.highlight(5) # the parameter is a color number"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 10
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The call of `highlight(5)` on the accepting run `r` modified the original automaton `b`:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "b"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 11,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d1b0> >"
- ]
- }
- ],
- "prompt_number": 11
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Highlighting from a product\n",
- "\n",
- "Pretty often, accepting runs are found in a product but we want to display them on one of the original automata. This can be done by projecting the runs on those automata before displaying them."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "left = spot.translate('a U b')\n",
- "right = spot.translate('GFa')\n",
- "display(left, right)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d2d0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d150> >"
- ]
- }
- ],
- "prompt_number": 12
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "prod = spot.product(left, right); prod"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 13,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d2a0> >"
- ]
- }
- ],
- "prompt_number": 13
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "run = prod.accepting_run(); run"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 14,
- "text": [
- "Prefix:\n",
- " 1,0\n",
- " | !a & b\n",
- "Cycle:\n",
- " 0,0\n",
- " | !a\t{0}\n",
- " 0,0\n",
- " | a\t{0,1}"
- ]
- }
- ],
- "prompt_number": 14
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "run.highlight(5)\n",
- "# Note that by default project() needs to know on which side you project, but it cannot \n",
- "# guess it. The left-side is assumed unless you pass True as a second argument.\n",
- "run.project(left).highlight(5)\n",
- "run.project(right, True).highlight(5)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [],
- "prompt_number": 15
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "display(prod, left, right)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d2a0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d2d0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d150> >"
- ]
- }
- ],
- "prompt_number": 16
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The projection also works for products generated on-the-fly, but the on-the-fly product itself cannot be highlighted (it does not store states or transitions). "
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "left2 = spot.translate('!b & FG a')\n",
- "right2 = spot.translate('XXXb')\n",
- "prod2 = spot.otf_product(left2, right2) # Note \"otf_product()\"\n",
- "run2 = prod2.accepting_run()\n",
- "run2.project(left2).highlight(5)\n",
- "run2.project(right2, True).highlight(5)\n",
- "display(run2, prod2, left2, right2)"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "text": [
- "Prefix:\n",
- " 0 * 3\n",
- " | a & !b\n",
- " 1 * 2\n",
- " | a\t{0}\n",
- " 1 * 1\n",
- " | a\t{0}\n",
- " 1 * 0\n",
- " | a & b\t{0}\n",
- "Cycle:\n",
- " 1 * 4\n",
- " | a\t{0,1}"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d210> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d1e0> >"
- ]
- },
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d270> >"
- ]
- }
- ],
- "prompt_number": 17
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Highlighting nondeterminism\n",
- "\n",
- "Sometimes its is hard to locate non-deterministic states inside a large automaton. Here are two functions that can help for that."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "b = spot.translate('X (F(Ga <-> b) & GF!b)')\n",
- "spot.highlight_nondet_states(b, 5)\n",
- "spot.highlight_nondet_edges(b, 4)\n",
- "b"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 18,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d330> >"
- ]
- }
- ],
- "prompt_number": 18
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Disappearing highlights\n",
- "\n",
- "As explained at the top of this notebook, named properties (such as highlights) are fragile, and you should not really on them being preserved across algorithms. In-place algorithm are probably the worst, because they might modify the automaton and ignore the attached named properties. \n",
- "\n",
- "`randomize()` is one such in-place algorithm: it reorder states or transitions of the automaton. By doing so it renumber the states and edges, and that process would completely invalidate the highlights information. Fortunately `randomize()` know about highlights: it will preserve highlighted states, but it will drop all highlighted edges."
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.randomize(b); b"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "pyout",
- "prompt_number": 19,
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text": [
- " *' at 0x7fe12058d330> >"
- ]
- }
- ],
- "prompt_number": 19
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Highlighting with partial output\n",
- "\n",
- "For simplicity, rendering of partial automata is actually implemented by copying the original automaton and marking some states as \"incomplete\". This also allows the same display code to work with automata generated on-the-fly. However since there is a copy, propagating the highlighting information requires extra work. Let's make sure it has been done:"
- ]
- },
- {
- "cell_type": "code",
- "collapsed": false,
- "input": [
- "spot.highlight_nondet_edges(b, 4) # let's get those highlighted edges back\n",
- "display(b, b.show('.<4'), b.show('.<2'))"
- ],
- "language": "python",
- "metadata": {},
- "outputs": [
- {
- "metadata": {},
- "output_type": "display_data",
- "svg": [
- "\n",
- "\n",
- "\n",
- "\n",
- "