diff --git a/tests/python/highlighting.ipynb b/tests/python/highlighting.ipynb index 1595234e6..5804bd265 100644 --- a/tests/python/highlighting.ipynb +++ b/tests/python/highlighting.ipynb @@ -17,7 +17,8 @@ "pygments_lexer": "ipython3", "version": "3.4.3+" }, - "name": "" + "name": "", + "signature": "sha256:0f4fb50930c6511a58891626864fe3236e91bb2525f9d8b2b1108f3e2a4c5d28" }, "nbformat": 3, "nbformat_minor": 0, @@ -29,13 +30,27 @@ "collapsed": false, "input": [ "import spot\n", - "spot.setup()" + "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, @@ -140,7 +155,7 @@ "" ], "text": [ - "" + "" ] } ], @@ -240,7 +255,7 @@ "\n" ], "text": [ - " *' at 0x7fd034659540> >" + " *' at 0x7f44a00f88a0> >" ] } ], @@ -342,7 +357,7 @@ "\n" ], "text": [ - " *' at 0x7fd034190180> >" + " *' at 0x7f44a006cf30> >" ] } ], @@ -352,6 +367,78 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "# Saving the 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 0\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": 6 + }, + { + "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." @@ -369,7 +456,7 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 6, + "prompt_number": 7, "svg": [ "\n", "\n" ], "text": [ - " *' at 0x7fd034190240> >" + " *' at 0x7f44a006cfc0> >" ] } ], - "prompt_number": 6 + "prompt_number": 7 }, { "cell_type": "code", @@ -503,7 +590,7 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 7, + "prompt_number": 8, "text": [ "Prefix:\n", " 0\n", @@ -516,7 +603,7 @@ ] } ], - "prompt_number": 7 + "prompt_number": 8 }, { "cell_type": "code", @@ -527,7 +614,14 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 8 + "prompt_number": 9 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The call of `highlight(5)` on the accepting run `r` modified the original automaton `b`:" + ] }, { "cell_type": "code", @@ -541,7 +635,7 @@ { "metadata": {}, "output_type": "pyout", - "prompt_number": 9, + "prompt_number": 10, "svg": [ "\n", "\n" ], "text": [ - " *' at 0x7fd034190240> >" + " *' at 0x7f44a006cfc0> >" ] } ], - "prompt_number": 9 + "prompt_number": 10 + }, + { + "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", + "\n", + "G\n", + "\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "I->1\n", + "\n", + "\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "a & !b\n", + "\n", + "\n", + "0\n", + "\n", + "\n", + "0\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "b\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f50f0> >" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "!a\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f50c0> >" + ] + } + ], + "prompt_number": 11 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "prod = spot.product(left, right); prod" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 12, + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "1,0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "a & !b\n", + "\u2776\n", + "\n", + "\n", + "1\n", + "\n", + "0,0\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "a & b\n", + "\u2776\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "!a & b\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\u2776\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "!a\n", + "\u24ff\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a006cf60> >" + ] + } + ], + "prompt_number": 12 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "run = spot.couvreur99(prod).check().accepting_run(); run" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 13, + "text": [ + "Prefix:\n", + " 0\n", + " | a & b\t{1}\n", + "Cycle:\n", + " 1\n", + " | a\t{0,1}" + ] + } + ], + "prompt_number": 13 + }, + { + "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": 14 + }, + { + "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", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "1,0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "a & !b\n", + "\u2776\n", + "\n", + "\n", + "1\n", + "\n", + "0,0\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "a & b\n", + "\u2776\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "!a & b\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\u2776\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "!a\n", + "\u24ff\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a006cf60> >" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "I->1\n", + "\n", + "\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "a & !b\n", + "\n", + "\n", + "0\n", + "\n", + "\n", + "0\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "b\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f50f0> >" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\n", + "\n", + "0->0\n", + "\n", + "\n", + "!a\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f50c0> >" + ] + } + ], + "prompt_number": 15 + }, + { + "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 = spot.couvreur99(prod2).check().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", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "0 * 3\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "1\n", + "\n", + "1 * 2\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "a & !b\n", + "\n", + "\n", + "2\n", + "\n", + "2 * 2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!b\n", + "\n", + "\n", + "3\n", + "\n", + "1 * 1\n", + "\n", + "\n", + "1->3\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\n", + "\n", + "2->3\n", + "\n", + "\n", + "a\n", + "\n", + "\n", + "4\n", + "\n", + "2 * 1\n", + "\n", + "\n", + "2->4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "5\n", + "\n", + "1 * 0\n", + "\n", + "\n", + "3->5\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\n", + "\n", + "4->5\n", + "\n", + "\n", + "a\n", + "\n", + "\n", + "6\n", + "\n", + "2 * 0\n", + "\n", + "\n", + "4->6\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "7\n", + "\n", + "1 * 4\n", + "\n", + "\n", + "5->7\n", + "\n", + "\n", + "a & b\n", + "\u24ff\n", + "\n", + "\n", + "6->7\n", + "\n", + "\n", + "a & b\n", + "\n", + "\n", + "8\n", + "\n", + "2 * 4\n", + "\n", + "\n", + "6->8\n", + "\n", + "\n", + "b\n", + "\n", + "\n", + "7->7\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\u2776\n", + "\n", + "\n", + "8->7\n", + "\n", + "\n", + "a\n", + "\u2776\n", + "\n", + "\n", + "8->8\n", + "\n", + "\n", + "1\n", + "\u2776\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f5120> >" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "a & !b\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "0->2\n", + "\n", + "\n", + "!b\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "a\n", + "\u24ff\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "a\n", + "\n", + "\n", + "2->2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f5060> >" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "I->3\n", + "\n", + "\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "3->2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "4\n", + "\n", + "\n", + "0->4\n", + "\n", + "\n", + "b\n", + "\n", + "\n", + "4->4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "1->0\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "2->1\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f5030> >" + ] + } + ], + "prompt_number": 16 + }, + { + "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": 17, + "svg": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "G\n", + "\n", + "\n", + "\n", + "0\n", + "\n", + "0\n", + "\n", + "\n", + "I->0\n", + "\n", + "\n", + "\n", + "\n", + "1\n", + "\n", + "1\n", + "\n", + "\n", + "0->1\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "1->1\n", + "\n", + "\n", + "a | b\n", + "\n", + "\n", + "2\n", + "\n", + "2\n", + "\n", + "\n", + "1->2\n", + "\n", + "\n", + "!a & !b\n", + "\n", + "\n", + "3\n", + "\n", + "3\n", + "\n", + "\n", + "1->3\n", + "\n", + "\n", + "a & b\n", + "\n", + "\n", + "4\n", + "\n", + "4\n", + "\n", + "\n", + "1->4\n", + "\n", + "\n", + "a & !b\n", + "\n", + "\n", + "2->2\n", + "\n", + "\n", + "b\n", + "\n", + "\n", + "2->2\n", + "\n", + "\n", + "!b\n", + "\u24ff\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "a & b\n", + "\n", + "\n", + "3->3\n", + "\n", + "\n", + "a & !b\n", + "\u24ff\n", + "\n", + "\n", + "4->2\n", + "\n", + "\n", + "!a & b\n", + "\n", + "\n", + "4->4\n", + "\n", + "\n", + "a & b\n", + "\n", + "\n", + "\n" + ], + "text": [ + " *' at 0x7f44a68f5210> >" + ] + } + ], + "prompt_number": 17 } ], "metadata": {}