spot/tests/python/stutter-inv.ipynb
2018-05-04 17:44:09 +02:00

2361 lines
144 KiB
Text

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import spot\n",
"spot.setup(show_default='.ban')\n",
"from IPython.display import display"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Stutter-invariant languages\n",
"\n",
"A language $L$ is said to be _stutter-invariant_ iff $\\ell_0\\ldots\\ell_{i-1}\\ell_i\\ell_{i+1}\\ldots\\in L \\iff \\ell_0\\ldots\\ell_{i-1}\\ell_i\\ell_i\\ell_{i+1}\\ldots\\in L$, i.e., if duplicating a letter in a word or removing a duplicated letter does not change the membership of that word to $L$. These languages are also called _stutter-insensitive_. We use the adjective _sutter-sensitive_ to describe a language that is not stutter-invariant. Of course we can extend this vocabulary to LTL formulas or automata that represent stutter-invariant languages.\n",
"\n",
"Stutter-invariant languages play an important role in model checking. When verifying a stutter-invariant specification against a system, we know that we have some freedom in how we discretize the time in the model: as long as we do not hide changes of model variables that are observed by the specification, we can merge multiple steps of the model. This, combined by careful analysis of actions of the model that are independent, is the basis for a set of techniques known as _partial-order reductions_ (POR) that postpone the visit of some successors in the model, because we know we can always visit them later."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Stutter-invariant formulas\n",
"\n",
"When the specification is expressed as an LTL formula, a well known way to ensure it is _stutter-invariant_ is to forbid the use of the `X` operator. Testing whether a formula is `X`-free can be done in constant time using the `is_syntactic_stutter_invariant()` method."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"f = spot.formula('a U b')\n",
"print(f.is_syntactic_stutter_invariant())"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n"
]
}
],
"source": [
"f = spot.formula('a U Xb')\n",
"print(f.is_syntactic_stutter_invariant())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However some formula are syntactic-invariant despite their use of `X`. Spot implements some [automaton-based check](https://www.lrde.epita.fr/~adl/dl/adl/michaud.15.spin.pdf) to detect stutter-invariance reliably and efficiently. This can be tested with the `is_stutter_invariant()` function."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n",
"True\n"
]
}
],
"source": [
"g = spot.formula('F(a & X(!a & Gb))')\n",
"print(g.is_syntactic_stutter_invariant())\n",
"print(spot.is_stutter_invariant(g))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Of course this `is_stutter_invariant()` function first checks whether the formula is `X`-free before wasting time building automata, so if you want to detect stutter-invariant formulas in your model checker, this is the only function to use. Also, if you hapen to already have an automaton `aut_g` for `g`, you should pass it as a second argument to avoid it being recomputed: `spot.is_stutter_invariant(g, aut_g)`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is also known that any stutter-invariant LTL formula can be converted to an `X`-free LTL formula. Several proofs of that exist. Spot implements the rewriting of [K. Etessami](http://homepages.inf.ed.ac.uk/kousha/note_on_stut_tl_lpi.ps) under the name `remove_x()`. Note that the output of this function is only equivalent to its input if the latter is stutter-invariant."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\mathsf{F} (a \\land ((a \\land (a \\mathbin{\\mathsf{U}} (\\lnot a \\land \\mathsf{G} 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 \\mathsf{G} b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} a) \\lor (b \\mathbin{\\mathsf{U}} a))) \\lor (b \\land (b \\mathbin{\\mathsf{U}} (\\lnot a \\land \\lnot b \\land \\mathsf{G} 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 \\mathsf{G} b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} b) \\lor (a \\mathbin{\\mathsf{U}} b))) \\lor (\\lnot a \\land \\mathsf{G} b \\land (\\mathsf{G} \\lnot a \\lor \\mathsf{G} a) \\land (\\mathsf{G} b \\lor \\mathsf{G} \\lnot b))))$"
],
"text/plain": [
"F(a & ((a & (a U (!a & Gb)) & ((!b U !a) | (b U !a))) | (!a & (!a U (a & !a & Gb)) & ((!b U a) | (b U a))) | (b & (b U (!a & !b & Gb)) & ((!a U !b) | (a U !b))) | (!b & (!b U (!a & b & Gb)) & ((!a U b) | (a U b))) | (!a & Gb & (G!a | Ga) & (Gb | G!b))))"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.remove_x(g)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Stutter-invariant automata"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly to formulas, automata use a few bits to store some known properties about themselves, like whether they represent a stutter-invariant language. This property can be checked with the `prop_stutter_invariant()` method, but that returns a `trival` instance (i.e., yes, no, or maybe). Some algorithms will update that property whenever that is cheap or expliclitely asked for. For instance `spot.translate()` only sets the property if the translated formula is `X`-free."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"maybe\n"
]
}
],
"source": [
"aut = spot.translate(g)\n",
"print(aut.prop_stutter_invariant())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As suggested above, we can call `is_stutter_invariant()` by passing a formula and its automaton, to save on one translation. A second translation is still needed to complement the automaton."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"print(spot.is_stutter_invariant(g, aut))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that `prop_stutter_invariant()` was updated as a side-effect so that any futher call to `is_stutter_invariant()` with this automaton will be instantaneous."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"yes\n"
]
}
],
"source": [
"print(aut.prop_stutter_invariant())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You have to be aware of this property being set in your back because if while playing with `is_stutter_invariant()` you the incorrect formula for an automaton by mistake, the automaton will have its property set incorrectly, and running `is_stutter_inariant()` with the correct formula will simply return the cached property.\n",
"\n",
"In doubt, you can always reset the property as follows:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"maybe\n"
]
}
],
"source": [
"aut.prop_stutter_invariant(spot.trival_maybe())\n",
"print(aut.prop_stutter_invariant())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In case you have an automaton for which you do not have formula, you can also use `is_stutter_invariant()` by passing this automaton as the first argument. In that case a negated automaton will be constructed by determinization. If you do happen to have a negated automaton handy, you can pass it as a second argument to avoid that."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"163pt\" height=\"84pt\"\n",
" viewBox=\"0.00 0.00 163.00 84.01\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 80.0147)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-80.0147 159,-80.0147 159,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"74.5\" y=\"-60.8147\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">t</text>\n",
"<text text-anchor=\"start\" x=\"66.5\" y=\"-45.8147\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[all]</text>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-20.0147\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-16.3147\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-20.0147C4.178,-20.0147 17.9448,-20.0147 30.9241,-20.0147\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-20.0147 30.9808,-23.1648 34.4807,-20.0147 30.9807,-20.0148 30.9807,-20.0148 30.9807,-20.0148 34.4807,-20.0147 30.9807,-16.8648 37.9807,-20.0147 37.9807,-20.0147\"/>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"137\" cy=\"-20.0147\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"137\" y=\"-16.3147\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M74.3802,-20.0147C85.4352,-20.0147 99.6622,-20.0147 111.7609,-20.0147\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"118.9716,-20.0147 111.9716,-23.1648 115.4716,-20.0147 111.9716,-20.0148 111.9716,-20.0148 111.9716,-20.0148 115.4716,-20.0147 111.9716,-16.8648 118.9716,-20.0147 118.9716,-20.0147\"/>\n",
"<text text-anchor=\"start\" x=\"93\" y=\"-23.8147\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M121.8943,-9.9447C115.6932,-6.3829 108.2713,-2.8158 101,-1.0147 92.807,1.0147 84.1826,-1.406 76.7006,-5.1232\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"70.1958,-8.811 74.7317,-2.6184 73.2405,-7.0848 76.2852,-5.3587 76.2852,-5.3587 76.2852,-5.3587 73.2405,-7.0848 77.8388,-8.0989 70.1958,-8.811 70.1958,-8.811\"/>\n",
"<text text-anchor=\"middle\" x=\"96.5\" y=\"-4.8147\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa2444ce810> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n"
]
}
],
"source": [
"a1 = spot.automaton('''HOA: v1 \n",
"AP: 1 \"a\" \n",
"States: 2 \n",
"Start: 0 \n",
"Acceptance: 0 t\n",
"--BODY-- \n",
"State: 0 [0] 1 \n",
"State: 1 [t] 0 \n",
"--END--''')\n",
"display(a1)\n",
"print(spot.is_stutter_invariant(a1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Explaining why a formula is not sutter-invariant"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As explained in our [Spin'15 paper](https://www.lrde.epita.fr/~adl/dl/adl/michaud.15.spin.pdf) the sutter-invariant checks are implemented using simple operators suchs as `spot.closure(aut)`, that augment the language of L by adding words that can be obtained by removing duplicated letters, and `spot.sl(aut)` or `spot.sl2(aut)` that both augment the language that L by adding words that can be obtained by duplicating letters. The default `is_stutter_invariant()` function is implemented as `spot.product(spot.closure(aut), spot.closure(neg_aut)).is_empty()`, but that is just one possible implementation selected because it was more efficient.\n",
"\n",
"Using these bricks, we can modify the original algorithm so it uses a counterexample to explain why a formula is stutter-sensitive."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"def explain_stut(f):\n",
" f = spot.formula(f)\n",
" pos = spot.translate(f)\n",
" neg = spot.translate(spot.formula_Not(f))\n",
" word = spot.product(spot.closure(pos), spot.closure(neg)).accepting_word()\n",
" if word is None:\n",
" print(f, \"is stutter invariant\")\n",
" return\n",
" word.simplify()\n",
" waut = word.as_automaton()\n",
" if waut.intersects(pos):\n",
" acc, rej, aut = \"accepted\", \"rejected\", neg\n",
" else:\n",
" acc, rej, aut = \"rejected\", \"accepted\", pos\n",
" word2 = spot.sl2(waut).intersecting_word(aut)\n",
" word2.simplify()\n",
" print(\"\"\"{} is {} by {}\n",
" but if we stutter some of its letters, we get\n",
"{} which is {} by {}\"\"\".format(word, acc, f, word2, rej, f))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cycle{!a & !b; a & b} is rejected by GF(a & Xb)\n",
" but if we stutter some of its letters, we get\n",
"cycle{!a & !b; a & b; a & b} which is accepted by GF(a & Xb)\n"
]
}
],
"source": [
"explain_stut('GF(a & Xb)')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Detecting stutter-invariant states\n",
"\n",
"Even if the language of an automaton is not sutter invariant, some of its states may recognize a stutter-invariant language. (We assume the language of a state is the language the automaton would have when starting from this state.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### First example\n",
"\n",
"For instance let us build a disjunction of a stutter-invariant formula and a stutter-sensitive one:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"False\n",
"False\n"
]
}
],
"source": [
"f1 = spot.formula('F(a & X!a & XF(b & X!b & Ga))')\n",
"f2 = spot.formula('F(a & Xa & XXa & G!b)')\n",
"f = spot.formula_Or([f1, f2])\n",
"\n",
"print(spot.is_stutter_invariant(f1))\n",
"print(spot.is_stutter_invariant(f2))\n",
"print(spot.is_stutter_invariant(f))"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"518pt\" height=\"230pt\"\n",
" viewBox=\"0.00 0.00 518.00 230.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 226)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-226 514,-226 514,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"234\" y=\"-207.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"256\" y=\"-207.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"272\" y=\"-207.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"232\" y=\"-193.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[Büchi]</text>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-81\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-77.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-81C4.178,-81 17.9448,-81 30.9241,-81\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-81 30.9808,-84.1501 34.4807,-81 30.9807,-81.0001 30.9807,-81.0001 30.9807,-81.0001 34.4807,-81 30.9807,-77.8501 37.9807,-81 37.9807,-81\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M49.6208,-98.0373C48.3189,-107.8579 50.4453,-117 56,-117 60.166,-117 62.4036,-111.8576 62.7128,-105.1433\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"62.3792,-98.0373 65.8541,-104.8818 62.5434,-101.5335 62.7076,-105.0296 62.7076,-105.0296 62.7076,-105.0296 62.5434,-101.5335 59.561,-105.1774 62.3792,-98.0373 62.3792,-98.0373\"/>\n",
"<text text-anchor=\"start\" x=\"51.5\" y=\"-120.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"165\" cy=\"-108\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"start\" x=\"160.5\" y=\"-104.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M73.5127,-85.338C91.6004,-89.8184 119.9794,-96.8481 140.3337,-101.89\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"147.1686,-103.5831 139.6165,-104.9575 143.7713,-102.7415 140.374,-101.8999 140.374,-101.8999 140.374,-101.8999 143.7713,-102.7415 141.1314,-98.8423 147.1686,-103.5831 147.1686,-103.5831\"/>\n",
"<text text-anchor=\"start\" x=\"107\" y=\"-102.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"165\" cy=\"-54\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"165\" y=\"-50.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;2 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M73.5753,-76.5941C79.4345,-75.1285 85.9976,-73.4903 92,-72 108.0742,-68.009 126.1473,-63.5524 140.2892,-60.0721\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"147.2947,-58.3488 141.2498,-63.0798 143.896,-59.1849 140.4973,-60.0209 140.4973,-60.0209 140.4973,-60.0209 143.896,-59.1849 139.7449,-56.9621 147.2947,-58.3488 147.2947,-58.3488\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-75.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"274\" cy=\"-114\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"274\" y=\"-110.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;3 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M182.9991,-108.9908C200.9861,-109.9809 228.7902,-111.5114 248.9323,-112.6201\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"255.9741,-113.0078 248.8115,-115.7682 252.4794,-112.8153 248.9847,-112.6229 248.9847,-112.6229 248.9847,-112.6229 252.4794,-112.8153 249.1579,-109.4777 255.9741,-113.0078 255.9741,-113.0078\"/>\n",
"<text text-anchor=\"start\" x=\"214\" y=\"-115.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g id=\"node6\" class=\"node\">\n",
"<title>5</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"274\" cy=\"-54\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"274\" y=\"-50.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">5</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;5 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>2&#45;&gt;5</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M183.4904,-54C201.3712,-54 228.6126,-54 248.5388,-54\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"255.7827,-54 248.7828,-57.1501 252.2827,-54 248.7827,-54.0001 248.7827,-54.0001 248.7827,-54.0001 252.2827,-54 248.7827,-50.8501 255.7827,-54 255.7827,-54\"/>\n",
"<text text-anchor=\"start\" x=\"201\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;3 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>3&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M264.7674,-129.5414C262.1685,-139.9087 265.2461,-150 274,-150 280.7022,-150 284.077,-144.0847 284.1245,-136.6591\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"283.2326,-129.5414 287.2286,-136.0955 283.6678,-133.0143 284.103,-136.4871 284.103,-136.4871 284.103,-136.4871 283.6678,-133.0143 280.9775,-136.8788 283.2326,-129.5414 283.2326,-129.5414\"/>\n",
"<text text-anchor=\"start\" x=\"269.5\" y=\"-153.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g id=\"node7\" class=\"node\">\n",
"<title>4</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"383\" cy=\"-120\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"383\" y=\"-116.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">4</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g id=\"edge8\" class=\"edge\">\n",
"<title>3&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M291.9991,-114.9908C309.9861,-115.9809 337.7902,-117.5114 357.9323,-118.6201\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"364.9741,-119.0078 357.8115,-121.7682 361.4794,-118.8153 357.9847,-118.6229 357.9847,-118.6229 357.9847,-118.6229 361.4794,-118.8153 358.1579,-115.4777 364.9741,-119.0078 364.9741,-119.0078\"/>\n",
"<text text-anchor=\"start\" x=\"311.5\" y=\"-121.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; b</text>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g id=\"node9\" class=\"node\">\n",
"<title>6</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"383\" cy=\"-18\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"383\" y=\"-14.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">6</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;6 -->\n",
"<g id=\"edge10\" class=\"edge\">\n",
"<title>5&#45;&gt;6</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M291.5127,-48.216C309.8157,-42.171 338.6565,-32.6456 359.0572,-25.9077\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"365.8901,-23.651 360.2311,-28.8374 362.5667,-24.7487 359.2432,-25.8463 359.2432,-25.8463 359.2432,-25.8463 362.5667,-24.7487 358.2553,-22.8552 365.8901,-23.651 365.8901,-23.651\"/>\n",
"<text text-anchor=\"start\" x=\"310\" y=\"-45.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 7 -->\n",
"<g id=\"node8\" class=\"node\">\n",
"<title>7</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"492\" cy=\"-120\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"492\" y=\"-116.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">7</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;7 -->\n",
"<g id=\"edge9\" class=\"edge\">\n",
"<title>4&#45;&gt;7</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M401.4904,-120C419.3712,-120 446.6126,-120 466.5388,-120\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"473.7827,-120 466.7828,-123.1501 470.2827,-120 466.7827,-120.0001 466.7827,-120.0001 466.7827,-120.0001 470.2827,-120 466.7827,-116.8501 473.7827,-120 473.7827,-120\"/>\n",
"<text text-anchor=\"start\" x=\"419\" y=\"-123.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 7&#45;&gt;7 -->\n",
"<g id=\"edge12\" class=\"edge\">\n",
"<title>7&#45;&gt;7</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M482.7674,-135.5414C480.1685,-145.9087 483.2461,-156 492,-156 498.7022,-156 502.077,-150.0847 502.1245,-142.6591\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"501.2326,-135.5414 505.2286,-142.0955 501.6678,-139.0143 502.103,-142.4871 502.103,-142.4871 502.103,-142.4871 501.6678,-139.0143 498.9775,-142.8788 501.2326,-135.5414 501.2326,-135.5414\"/>\n",
"<text text-anchor=\"start\" x=\"488.5\" y=\"-174.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"484\" y=\"-159.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;6 -->\n",
"<g id=\"edge11\" class=\"edge\">\n",
"<title>6&#45;&gt;6</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M373.7674,-33.5414C371.1685,-43.9087 374.2461,-54 383,-54 389.7022,-54 393.077,-48.0847 393.1245,-40.6591\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"392.2326,-33.5414 396.2286,-40.0955 392.6678,-37.0143 393.103,-40.4871 393.103,-40.4871 393.103,-40.4871 392.6678,-37.0143 389.9775,-40.8788 392.2326,-33.5414 392.2326,-33.5414\"/>\n",
"<text text-anchor=\"start\" x=\"376.5\" y=\"-72.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!b</text>\n",
"<text text-anchor=\"start\" x=\"375\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa24445d270> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"pos = spot.translate(f)\n",
"display(pos)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"While the automaton as a whole is stutter-sensitive, we can see that eventually we will enter a sub-automaton that is stutter-invariant.\n",
"\n",
"The `stutter_invariant_states()` function returns a Boolean vector indiced by the state number. A state is marked as `True` if either its language is stutter-invariant, or if it can only be reached via a stutter-invariant state (see the second example later). As always, the second argument, `f`, can be omitted (pass `None`) if the formula is unknown, or it can be replaced by a negated automaton if it is known. "
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(False, True, False, True, True, True, True, True)"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.stutter_invariant_states(pos, f)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For convenience, the `highligh_...()` version colors the stutter-invariant states of the automaton for display.\n",
"(That 5 is the color number for red in Spot's hard-coded palette.)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"518pt\" height=\"230pt\"\n",
" viewBox=\"0.00 0.00 518.00 230.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 226)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-226 514,-226 514,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"234\" y=\"-207.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"256\" y=\"-207.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"272\" y=\"-207.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"232\" y=\"-193.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[Büchi]</text>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-81\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-77.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-81C4.178,-81 17.9448,-81 30.9241,-81\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-81 30.9808,-84.1501 34.4807,-81 30.9807,-81.0001 30.9807,-81.0001 30.9807,-81.0001 34.4807,-81 30.9807,-77.8501 37.9807,-81 37.9807,-81\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M49.6208,-98.0373C48.3189,-107.8579 50.4453,-117 56,-117 60.166,-117 62.4036,-111.8576 62.7128,-105.1433\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"62.3792,-98.0373 65.8541,-104.8818 62.5434,-101.5335 62.7076,-105.0296 62.7076,-105.0296 62.7076,-105.0296 62.5434,-101.5335 59.561,-105.1774 62.3792,-98.0373 62.3792,-98.0373\"/>\n",
"<text text-anchor=\"start\" x=\"51.5\" y=\"-120.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"165\" cy=\"-108\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"start\" x=\"160.5\" y=\"-104.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M73.5127,-85.338C91.6004,-89.8184 119.9794,-96.8481 140.3337,-101.89\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"147.1686,-103.5831 139.6165,-104.9575 143.7713,-102.7415 140.374,-101.8999 140.374,-101.8999 140.374,-101.8999 143.7713,-102.7415 141.1314,-98.8423 147.1686,-103.5831 147.1686,-103.5831\"/>\n",
"<text text-anchor=\"start\" x=\"107\" y=\"-102.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"165\" cy=\"-54\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"165\" y=\"-50.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;2 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M73.5753,-76.5941C79.4345,-75.1285 85.9976,-73.4903 92,-72 108.0742,-68.009 126.1473,-63.5524 140.2892,-60.0721\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"147.2947,-58.3488 141.2498,-63.0798 143.896,-59.1849 140.4973,-60.0209 140.4973,-60.0209 140.4973,-60.0209 143.896,-59.1849 139.7449,-56.9621 147.2947,-58.3488 147.2947,-58.3488\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-75.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"274\" cy=\"-114\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"274\" y=\"-110.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;3 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M182.9991,-108.9908C200.9861,-109.9809 228.7902,-111.5114 248.9323,-112.6201\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"255.9741,-113.0078 248.8115,-115.7682 252.4794,-112.8153 248.9847,-112.6229 248.9847,-112.6229 248.9847,-112.6229 252.4794,-112.8153 249.1579,-109.4777 255.9741,-113.0078 255.9741,-113.0078\"/>\n",
"<text text-anchor=\"start\" x=\"214\" y=\"-115.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g id=\"node6\" class=\"node\">\n",
"<title>5</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"274\" cy=\"-54\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"274\" y=\"-50.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">5</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;5 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>2&#45;&gt;5</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M183.4904,-54C201.3712,-54 228.6126,-54 248.5388,-54\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"255.7827,-54 248.7828,-57.1501 252.2827,-54 248.7827,-54.0001 248.7827,-54.0001 248.7827,-54.0001 252.2827,-54 248.7827,-50.8501 255.7827,-54 255.7827,-54\"/>\n",
"<text text-anchor=\"start\" x=\"201\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;3 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>3&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M264.7674,-129.5414C262.1685,-139.9087 265.2461,-150 274,-150 280.7022,-150 284.077,-144.0847 284.1245,-136.6591\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"283.2326,-129.5414 287.2286,-136.0955 283.6678,-133.0143 284.103,-136.4871 284.103,-136.4871 284.103,-136.4871 283.6678,-133.0143 280.9775,-136.8788 283.2326,-129.5414 283.2326,-129.5414\"/>\n",
"<text text-anchor=\"start\" x=\"269.5\" y=\"-153.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g id=\"node7\" class=\"node\">\n",
"<title>4</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"383\" cy=\"-120\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"383\" y=\"-116.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">4</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g id=\"edge8\" class=\"edge\">\n",
"<title>3&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M291.9991,-114.9908C309.9861,-115.9809 337.7902,-117.5114 357.9323,-118.6201\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"364.9741,-119.0078 357.8115,-121.7682 361.4794,-118.8153 357.9847,-118.6229 357.9847,-118.6229 357.9847,-118.6229 361.4794,-118.8153 358.1579,-115.4777 364.9741,-119.0078 364.9741,-119.0078\"/>\n",
"<text text-anchor=\"start\" x=\"311.5\" y=\"-121.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; b</text>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g id=\"node9\" class=\"node\">\n",
"<title>6</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"383\" cy=\"-18\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"383\" y=\"-14.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">6</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;6 -->\n",
"<g id=\"edge10\" class=\"edge\">\n",
"<title>5&#45;&gt;6</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M291.5127,-48.216C309.8157,-42.171 338.6565,-32.6456 359.0572,-25.9077\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"365.8901,-23.651 360.2311,-28.8374 362.5667,-24.7487 359.2432,-25.8463 359.2432,-25.8463 359.2432,-25.8463 362.5667,-24.7487 358.2553,-22.8552 365.8901,-23.651 365.8901,-23.651\"/>\n",
"<text text-anchor=\"start\" x=\"310\" y=\"-45.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 7 -->\n",
"<g id=\"node8\" class=\"node\">\n",
"<title>7</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"492\" cy=\"-120\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"492\" y=\"-116.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">7</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;7 -->\n",
"<g id=\"edge9\" class=\"edge\">\n",
"<title>4&#45;&gt;7</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M401.4904,-120C419.3712,-120 446.6126,-120 466.5388,-120\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"473.7827,-120 466.7828,-123.1501 470.2827,-120 466.7827,-120.0001 466.7827,-120.0001 466.7827,-120.0001 470.2827,-120 466.7827,-116.8501 473.7827,-120 473.7827,-120\"/>\n",
"<text text-anchor=\"start\" x=\"419\" y=\"-123.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 7&#45;&gt;7 -->\n",
"<g id=\"edge12\" class=\"edge\">\n",
"<title>7&#45;&gt;7</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M482.7674,-135.5414C480.1685,-145.9087 483.2461,-156 492,-156 498.7022,-156 502.077,-150.0847 502.1245,-142.6591\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"501.2326,-135.5414 505.2286,-142.0955 501.6678,-139.0143 502.103,-142.4871 502.103,-142.4871 502.103,-142.4871 501.6678,-139.0143 498.9775,-142.8788 501.2326,-135.5414 501.2326,-135.5414\"/>\n",
"<text text-anchor=\"start\" x=\"488.5\" y=\"-174.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"484\" y=\"-159.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;6 -->\n",
"<g id=\"edge11\" class=\"edge\">\n",
"<title>6&#45;&gt;6</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M373.7674,-33.5414C371.1685,-43.9087 374.2461,-54 383,-54 389.7022,-54 393.077,-48.0847 393.1245,-40.6591\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"392.2326,-33.5414 396.2286,-40.0955 392.6678,-37.0143 393.103,-40.4871 393.103,-40.4871 393.103,-40.4871 392.6678,-37.0143 389.9775,-40.8788 392.2326,-33.5414 392.2326,-33.5414\"/>\n",
"<text text-anchor=\"start\" x=\"376.5\" y=\"-72.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!b</text>\n",
"<text text-anchor=\"start\" x=\"375\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa24445d270> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"spot.highlight_stutter_invariant_states(pos, f, 5)\n",
"display(pos)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Such a procedure gives us map of where POR can be enabled when model checking using such an automaton."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Second example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This second example illustrates the fact that a state can be marked if it it not sutter-invariant but appear below a stutter-invariant state. We build our example automaton as the disjuction of the following two stutter-sensitive formulas, whose union is equivalent to the sutter-invariant formula `GF!a`."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"g1 = spot.formula('GF(a & Xa) & GF!a')\n",
"g2 = spot.formula('!GF(a & Xa) & GF!a')\n",
"g = spot.formula_Or([g1, g2])"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n",
"False\n",
"True\n"
]
}
],
"source": [
"print(spot.is_stutter_invariant(g1))\n",
"print(spot.is_stutter_invariant(g2))\n",
"print(spot.is_stutter_invariant(g))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here are the automata for `g1` and `g2`, note that none of the states are stutter-invariant."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Title: G(F(a &amp; Xa) &amp; F!a) Pages: 1 -->\n",
"<svg width=\"170pt\" height=\"178pt\"\n",
" viewBox=\"0.00 0.00 170.00 177.59\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 173.5945)\">\n",
"<title>G(F(a &amp; Xa) &amp; F!a)</title>\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-173.5945 166,-173.5945 166,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"25\" y=\"-155.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">G(F(a &amp; Xa) &amp; F!a)</text>\n",
"<text text-anchor=\"start\" x=\"34\" y=\"-141.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"56\" y=\"-141.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"72\" y=\"-141.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)&amp;Inf(</text>\n",
"<text text-anchor=\"start\" x=\"108\" y=\"-141.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"<text text-anchor=\"start\" x=\"124\" y=\"-141.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"37\" y=\"-127.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[gen. Büchi 2]</text>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-20.5945\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-16.8945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-20.5945C4.178,-20.5945 17.9448,-20.5945 30.9241,-20.5945\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-20.5945 30.9808,-23.7446 34.4807,-20.5946 30.9807,-20.5946 30.9807,-20.5946 30.9807,-20.5946 34.4807,-20.5946 30.9807,-17.4446 37.9807,-20.5945 37.9807,-20.5945\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M52.7643,-38.3763C52.2144,-47.9095 53.293,-56.5945 56,-56.5945 57.988,-56.5945 59.0977,-51.9106 59.3292,-45.6466\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"59.2357,-38.3763 62.4756,-45.3351 59.2808,-41.876 59.3258,-45.3757 59.3258,-45.3757 59.3258,-45.3757 59.2808,-41.876 56.1761,-45.4162 59.2357,-38.3763 59.2357,-38.3763\"/>\n",
"<text text-anchor=\"start\" x=\"50.5\" y=\"-75.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"48\" y=\"-60.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M50.9906,-38.1717C47.5451,-59.3126 49.2148,-86.5945 56,-86.5945 62.043,-86.5945 64.0285,-64.9541 61.9564,-45.2852\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"61.0094,-38.1717 65.0556,-44.6947 61.4713,-41.6411 61.9332,-45.1105 61.9332,-45.1105 61.9332,-45.1105 61.4713,-41.6411 58.8107,-45.5262 61.0094,-38.1717 61.0094,-38.1717\"/>\n",
"<text text-anchor=\"start\" x=\"52.5\" y=\"-90.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"144\" cy=\"-20.5945\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"144\" y=\"-16.8945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M74.2337,-20.5945C87.0948,-20.5945 104.4907,-20.5945 118.6942,-20.5945\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"125.7897,-20.5945 118.7897,-23.7446 122.2897,-20.5946 118.7897,-20.5946 118.7897,-20.5946 118.7897,-20.5946 122.2897,-20.5946 118.7897,-17.4446 125.7897,-20.5945 125.7897,-20.5945\"/>\n",
"<text text-anchor=\"start\" x=\"96.5\" y=\"-39.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-24.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M129.247,-10.1729C118.9796,-4.1758 104.8748,1.5945 92,-1.5945 87.1146,-2.8046 82.1612,-4.8119 77.5558,-7.0792\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"71.1057,-10.5245 75.7959,-4.448 74.1929,-8.8755 77.2801,-7.2264 77.2801,-7.2264 77.2801,-7.2264 74.1929,-8.8755 78.7642,-10.0049 71.1057,-10.5245 71.1057,-10.5245\"/>\n",
"<text text-anchor=\"start\" x=\"96.5\" y=\"-5.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M136.3321,-36.8848C134.4831,-46.9837 137.0391,-56.5945 144,-56.5945 149.2207,-56.5945 151.9636,-51.1884 152.2287,-44.2249\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"151.6679,-36.8848 155.3421,-43.6244 151.9346,-40.3746 152.2013,-43.8645 152.2013,-43.8645 152.2013,-43.8645 151.9346,-40.3746 149.0604,-44.1045 151.6679,-36.8848 151.6679,-36.8848\"/>\n",
"<text text-anchor=\"start\" x=\"140.5\" y=\"-75.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"136\" y=\"-60.3945\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa2444ce8a0> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Title: FG(!a | X!a) Pages: 1 -->\n",
"<svg width=\"253pt\" height=\"177pt\"\n",
" viewBox=\"0.00 0.00 253.00 177.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 173)\">\n",
"<title>FG(!a | X!a)</title>\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-173 249,-173 249,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"88.5\" y=\"-154.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">FG(!a | X!a)</text>\n",
"<text text-anchor=\"start\" x=\"101.5\" y=\"-140.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"123.5\" y=\"-140.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"139.5\" y=\"-140.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"99.5\" y=\"-126.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[Büchi]</text>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-18\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-14.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-18C4.178,-18 17.9448,-18 30.9241,-18\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-18 30.9808,-21.1501 34.4807,-18 30.9807,-18.0001 30.9807,-18.0001 30.9807,-18.0001 34.4807,-18 30.9807,-14.8501 37.9807,-18 37.9807,-18\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M49.6208,-35.0373C48.3189,-44.8579 50.4453,-54 56,-54 60.166,-54 62.4036,-48.8576 62.7128,-42.1433\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"62.3792,-35.0373 65.8541,-41.8818 62.5434,-38.5335 62.7076,-42.0296 62.7076,-42.0296 62.7076,-42.0296 62.5434,-38.5335 59.561,-42.1774 62.3792,-35.0373 62.3792,-35.0373\"/>\n",
"<text text-anchor=\"start\" x=\"51.5\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"139\" cy=\"-53\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"start\" x=\"134.5\" y=\"-49.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M72.7963,-25.0828C85.0589,-30.2538 101.8459,-37.3326 115.4473,-43.0681\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"122.2287,-45.9278 114.5547,-46.1103 119.0037,-44.5678 115.7787,-43.2078 115.7787,-43.2078 115.7787,-43.2078 119.0037,-44.5678 117.0027,-40.3053 122.2287,-45.9278 122.2287,-45.9278\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-40.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"227\" cy=\"-35\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"227\" y=\"-31.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;2 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M73.6356,-14.3004C93.8872,-10.6235 128.0462,-6.1744 157,-11 173.0791,-13.6799 190.4153,-19.599 203.8126,-24.888\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"210.4319,-27.5759 202.761,-27.8608 207.1891,-26.2591 203.9462,-24.9422 203.9462,-24.9422 203.9462,-24.9422 207.1891,-26.2591 205.1314,-22.0237 210.4319,-27.5759 210.4319,-27.5759\"/>\n",
"<text text-anchor=\"start\" x=\"135.5\" y=\"-14.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M131.9688,-69.6641C130.4063,-79.625 132.75,-89 139,-89 143.6875,-89 146.1777,-83.7266 146.4707,-76.8876\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"146.0313,-69.6641 149.6006,-76.4598 146.2438,-73.1576 146.4564,-76.6511 146.4564,-76.6511 146.4564,-76.6511 146.2438,-73.1576 143.3122,-76.8425 146.0313,-69.6641 146.0313,-69.6641\"/>\n",
"<text text-anchor=\"start\" x=\"133.5\" y=\"-107.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"131\" y=\"-92.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;2 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>1&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M154.7448,-61.7947C165.2012,-66.4602 179.1355,-70.4044 191,-66 197.9591,-63.4166 204.4745,-58.8182 209.9981,-53.9409\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"215.1708,-49.0349 212.2596,-56.1375 212.6314,-51.4434 210.0919,-53.852 210.0919,-53.852 210.0919,-53.852 212.6314,-51.4434 207.9242,-51.5664 215.1708,-49.0349 215.1708,-49.0349\"/>\n",
"<text text-anchor=\"start\" x=\"179.5\" y=\"-85.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"175\" y=\"-70.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;1 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>2&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M209.3802,-31.2344C199.1736,-29.7292 186.1736,-28.9792 175,-32 169.8137,-33.4021 164.6075,-35.7575 159.8291,-38.3951\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"153.6205,-42.104 158.0145,-35.8099 156.6252,-40.3091 159.6299,-38.5141 159.6299,-38.5141 159.6299,-38.5141 156.6252,-40.3091 161.2454,-41.2184 153.6205,-42.104 153.6205,-42.104\"/>\n",
"<text text-anchor=\"start\" x=\"177.5\" y=\"-50.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"175\" y=\"-35.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa24446e5d0> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"aut1 = spot.translate(g1)\n",
"aut1.set_name(str(g1))\n",
"spot.highlight_stutter_invariant_states(aut1, g1, 5)\n",
"display(aut1)\n",
"\n",
"aut2 = spot.translate(g2)\n",
"aut2.set_name(str(g2))\n",
"spot.highlight_stutter_invariant_states(aut2, g2, 5)\n",
"display(aut2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we build the sum of these two automata. The stutter-invariance check detects that the initial state is stutter-invariant (i.e., the entire language is stutter-invariant) so all states below it are marked despite the fact that the language recognized from these individual states would not be stutter-invariant."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"338pt\" height=\"360pt\"\n",
" viewBox=\"0.00 0.00 337.98 360.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(.997 .997) rotate(0) translate(4 357.0877)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-357.0877 335,-357.0877 335,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"89\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">(Inf(</text>\n",
"<text text-anchor=\"start\" x=\"114\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"130\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)&amp;Inf(</text>\n",
"<text text-anchor=\"start\" x=\"166\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"<text text-anchor=\"start\" x=\"182\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)) | Inf(</text>\n",
"<text text-anchor=\"start\" x=\"222\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff7f00\">❷</text>\n",
"<text text-anchor=\"start\" x=\"238\" y=\"-338.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"130.5\" y=\"-324.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[Fin&#45;less 3]</text>\n",
"<!-- I -->\n",
"<!-- 5 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>5</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"56\" cy=\"-80.0877\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-76.3877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">5</text>\n",
"</g>\n",
"<!-- I&#45;&gt;5 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;5</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-80.0877C4.178,-80.0877 17.9448,-80.0877 30.9241,-80.0877\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-80.0877 30.9808,-83.2378 34.4807,-80.0878 30.9807,-80.0878 30.9807,-80.0878 30.9807,-80.0878 34.4807,-80.0878 30.9807,-76.9378 37.9807,-80.0877 37.9807,-80.0877\"/>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"137\" cy=\"-218.0877\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"137\" y=\"-214.3877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;0 -->\n",
"<g id=\"edge16\" class=\"edge\">\n",
"<title>5&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M59.2987,-97.858C63.9004,-119.1522 73.8056,-155.195 92,-181.0877 98.2094,-189.9244 107.068,-197.8267 115.2855,-204.0366\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"121.3899,-208.443 113.8704,-206.9001 118.552,-206.3945 115.7141,-204.346 115.7141,-204.346 115.7141,-204.346 118.552,-206.3945 117.5577,-201.7919 121.3899,-208.443 121.3899,-208.443\"/>\n",
"<text text-anchor=\"middle\" x=\"96.5\" y=\"-193.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"225\" cy=\"-200.0877\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"225\" y=\"-196.3877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;1 -->\n",
"<g id=\"edge14\" class=\"edge\">\n",
"<title>5&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M68.2009,-93.4848C80.3253,-106.3497 99.8305,-125.8734 119,-140.0877 145.785,-159.9489 179.7906,-178.1074 201.959,-189.1251\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"208.4376,-192.3091 200.7659,-192.0486 205.2965,-190.7653 202.1553,-189.2215 202.1553,-189.2215 202.1553,-189.2215 205.2965,-190.7653 203.5447,-186.3945 208.4376,-192.3091 208.4376,-192.3091\"/>\n",
"<text text-anchor=\"start\" x=\"133.5\" y=\"-166.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"137\" cy=\"-80.0877\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"137\" y=\"-76.3877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;2 -->\n",
"<g id=\"edge17\" class=\"edge\">\n",
"<title>5&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M74.3802,-80.0877C85.4352,-80.0877 99.6622,-80.0877 111.7609,-80.0877\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"118.9716,-80.0877 111.9716,-83.2378 115.4716,-80.0878 111.9716,-80.0878 111.9716,-80.0878 111.9716,-80.0878 115.4716,-80.0878 111.9716,-76.9378 118.9716,-80.0877 118.9716,-80.0877\"/>\n",
"<text text-anchor=\"middle\" x=\"96.5\" y=\"-83.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g id=\"node6\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"225\" cy=\"-29.0877\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"225\" y=\"-25.3877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;3 -->\n",
"<g id=\"edge13\" class=\"edge\">\n",
"<title>5&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M69.8854,-67.7957C81.9568,-57.8966 100.387,-44.5955 119,-38.0877 145.4712,-28.8324 177.8303,-27.3899 199.781,-27.7483\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"206.8025,-27.9302 199.7233,-30.8978 203.3037,-27.8396 199.8049,-27.7489 199.8049,-27.7489 199.8049,-27.7489 203.3037,-27.8396 199.8865,-24.5999 206.8025,-27.9302 206.8025,-27.9302\"/>\n",
"<text text-anchor=\"start\" x=\"131.5\" y=\"-41.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g id=\"node7\" class=\"node\">\n",
"<title>4</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"313\" cy=\"-48.0877\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"313\" y=\"-44.3877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">4</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;4 -->\n",
"<g id=\"edge15\" class=\"edge\">\n",
"<title>5&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M67.4988,-66.1689C74.1904,-58.5484 83.0511,-49.2313 92,-42.0877 134.2921,-8.3271 153.0916,-6.8079 207,-2.0877 238.6063,.6797 250.0958,.7284 277,-16.0877 283.3819,-20.0767 289.726,-25.216 295.2701,-30.2037\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"300.5193,-35.0928 293.25,-32.6269 297.9581,-32.7073 295.3969,-30.3219 295.3969,-30.3219 295.3969,-30.3219 297.9581,-32.7073 297.5439,-28.0168 300.5193,-35.0928 300.5193,-35.0928\"/>\n",
"<text text-anchor=\"start\" x=\"177.5\" y=\"-8.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M133.4047,-235.8695C132.7938,-245.4027 133.9922,-254.0877 137,-254.0877 139.2089,-254.0877 140.4419,-249.4038 140.6991,-243.1398\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"140.5953,-235.8695 143.845,-242.8237 140.6453,-239.3691 140.6954,-242.8687 140.6954,-242.8687 140.6954,-242.8687 140.6453,-239.3691 137.5457,-242.9138 140.5953,-235.8695 140.5953,-235.8695\"/>\n",
"<text text-anchor=\"start\" x=\"131.5\" y=\"-272.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"129\" y=\"-257.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M131.494,-235.3368C127.5865,-256.5223 129.4219,-284.0877 137,-284.0877 143.7493,-284.0877 145.9433,-262.2225 143.582,-242.4728\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"142.506,-235.3368 146.6646,-241.7888 143.0279,-238.7976 143.5498,-242.2585 143.5498,-242.2585 143.5498,-242.2585 143.0279,-238.7976 140.435,-242.7282 142.506,-235.3368 142.506,-235.3368\"/>\n",
"<text text-anchor=\"start\" x=\"133.5\" y=\"-287.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M152.6013,-208.9598C158.7477,-205.8411 166.0013,-202.7279 173,-201.0877 181.5673,-199.0799 191.1475,-198.4558 199.7278,-198.4529\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"206.96,-198.5911 199.9011,-201.6067 203.4607,-198.5242 199.9613,-198.4573 199.9613,-198.4573 199.9613,-198.4573 203.4607,-198.5242 200.0216,-195.3079 206.96,-198.5911 206.96,-198.5911\"/>\n",
"<text text-anchor=\"start\" x=\"177.5\" y=\"-219.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"173\" y=\"-204.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M213.1708,-214.1226C206.7688,-220.6164 198.2788,-227.6432 189,-231.0877 179.5455,-234.5975 168.7766,-232.8058 159.5007,-229.5722\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"152.7448,-226.8824 160.4135,-226.5452 155.9966,-228.1771 159.2483,-229.4718 159.2483,-229.4718 159.2483,-229.4718 155.9966,-228.1771 158.0831,-232.3984 152.7448,-226.8824 152.7448,-226.8824\"/>\n",
"<text text-anchor=\"start\" x=\"177.5\" y=\"-235.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M217.3321,-216.378C215.4831,-226.4769 218.0391,-236.0877 225,-236.0877 230.2207,-236.0877 232.9636,-230.6816 233.2287,-223.7181\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"232.6679,-216.378 236.3421,-223.1176 232.9346,-219.8678 233.2013,-223.3577 233.2013,-223.3577 233.2013,-223.3577 232.9346,-219.8678 230.0604,-223.5977 232.6679,-216.378 232.6679,-216.378\"/>\n",
"<text text-anchor=\"start\" x=\"221.5\" y=\"-254.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"217\" y=\"-239.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;2 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>2&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M129.9688,-96.7518C128.4063,-106.7127 130.75,-116.0877 137,-116.0877 141.6875,-116.0877 144.1777,-110.8143 144.4707,-103.9753\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"144.0313,-96.7518 147.6006,-103.5475 144.2438,-100.2453 144.4564,-103.7389 144.4564,-103.7389 144.4564,-103.7389 144.2438,-100.2453 141.3122,-103.9302 144.0313,-96.7518 144.0313,-96.7518\"/>\n",
"<text text-anchor=\"middle\" x=\"137\" y=\"-119.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;3 -->\n",
"<g id=\"edge8\" class=\"edge\">\n",
"<title>2&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M152.7326,-70.9699C166.7481,-62.8473 187.3994,-50.879 203.0408,-41.8141\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"209.4036,-38.1266 204.9266,-44.362 206.3754,-39.8816 203.3471,-41.6366 203.3471,-41.6366 203.3471,-41.6366 206.3754,-39.8816 201.7676,-38.9112 209.4036,-38.1266 209.4036,-38.1266\"/>\n",
"<text text-anchor=\"start\" x=\"175.5\" y=\"-62.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;4 -->\n",
"<g id=\"edge9\" class=\"edge\">\n",
"<title>2&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M153.1296,-88.1435C173.8803,-97.4931 211.0592,-110.8204 243,-104.0877 259.1612,-100.6811 263.6823,-98.8565 277,-89.0877 284.7574,-83.3976 292.0258,-75.7692 297.9722,-68.636\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"302.638,-62.8141 300.7185,-70.2464 300.4492,-65.5453 298.2604,-68.2764 298.2604,-68.2764 298.2604,-68.2764 300.4492,-65.5453 295.8024,-66.3065 302.638,-62.8141 302.638,-62.8141\"/>\n",
"<text text-anchor=\"start\" x=\"221.5\" y=\"-108.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;3 -->\n",
"<g id=\"edge10\" class=\"edge\">\n",
"<title>3&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M217.3321,-45.378C215.4831,-55.4769 218.0391,-65.0877 225,-65.0877 230.2207,-65.0877 232.9636,-59.6816 233.2287,-52.7181\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"232.6679,-45.378 236.3421,-52.1176 232.9346,-48.8678 233.2013,-52.3577 233.2013,-52.3577 233.2013,-52.3577 232.9346,-48.8678 230.0604,-52.5977 232.6679,-45.378 232.6679,-45.378\"/>\n",
"<text text-anchor=\"start\" x=\"219.5\" y=\"-83.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"217\" y=\"-68.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff7f00\">❷</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g id=\"edge11\" class=\"edge\">\n",
"<title>3&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M242.1973,-23.5921C252.4927,-21.1595 265.7259,-19.557 277,-23.0877 282.9499,-24.951 288.779,-28.1827 293.9551,-31.7158\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"299.6996,-35.938 292.1937,-34.3305 296.8794,-33.8652 294.0593,-31.7923 294.0593,-31.7923 294.0593,-31.7923 296.8794,-33.8652 295.9248,-29.2542 299.6996,-35.938 299.6996,-35.938\"/>\n",
"<text text-anchor=\"start\" x=\"265.5\" y=\"-41.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"261\" y=\"-26.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff7f00\">❷</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;3 -->\n",
"<g id=\"edge12\" class=\"edge\">\n",
"<title>4&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M295.3331,-53.1108C285.1107,-55.2018 272.1107,-56.4518 261,-53.0877 255.3385,-51.3735 249.7535,-48.4429 244.7337,-45.2064\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"238.7143,-41.0119 246.2584,-42.4296 241.5859,-43.0129 244.4575,-45.014 244.4575,-45.014 244.4575,-45.014 241.5859,-43.0129 242.6565,-47.5984 238.7143,-41.0119 238.7143,-41.0119\"/>\n",
"<text text-anchor=\"start\" x=\"263.5\" y=\"-73.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"261\" y=\"-58.8877\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff7f00\">❷</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa24446e660> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"aut = spot.sum(aut1, aut2)\n",
"# At this point it is unknown if AUT is stutter-invariant\n",
"assert(aut.prop_stutter_invariant().is_maybe())\n",
"spot.highlight_stutter_invariant_states(aut, g, 5)\n",
"display(aut)\n",
"# The stutter_invariant property is set on AUT as a side effect\n",
"# of calling sutter_invariant_states() or any variant of it.\n",
"assert(aut.prop_stutter_invariant().is_true())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Third example\n",
"\n",
"These procedures work regardless of the acceptance condition. Here is an example with co-Büchi acceptance.\n",
"\n",
"In this case we do not even have a formula to pass as second argument, so the check will perform a complementation by determinization."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"349pt\" height=\"122pt\"\n",
" viewBox=\"0.00 0.00 348.74 121.87\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 117.8701)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-117.8701 344.7401,-117.8701 344.7401,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"147.8701\" y=\"-99.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Fin(</text>\n",
"<text text-anchor=\"start\" x=\"172.8701\" y=\"-99.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"188.8701\" y=\"-99.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"137.8701\" y=\"-85.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[co&#45;Büchi]</text>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-26.8701\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-23.1701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-26.8701C4.178,-26.8701 17.9448,-26.8701 30.9241,-26.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-26.8701 30.9808,-30.0202 34.4807,-26.8701 30.9807,-26.8702 30.9807,-26.8702 30.9807,-26.8702 34.4807,-26.8701 30.9807,-23.7202 37.9807,-26.8701 37.9807,-26.8701\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M49.6208,-43.9074C48.3189,-53.728 50.4453,-62.8701 56,-62.8701 60.166,-62.8701 62.4036,-57.7276 62.7128,-51.0134\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"62.3792,-43.9074 65.8541,-50.7519 62.5434,-47.4035 62.7076,-50.8997 62.7076,-50.8997 62.7076,-50.8997 62.5434,-47.4035 59.561,-51.0474 62.3792,-43.9074 62.3792,-43.9074\"/>\n",
"<text text-anchor=\"start\" x=\"52.5\" y=\"-66.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"139\" cy=\"-26.8701\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"139\" y=\"-23.1701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;2 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M74.0098,-26.8701C85.5679,-26.8701 100.7507,-26.8701 113.5345,-26.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"120.7388,-26.8701 113.7388,-30.0202 117.2388,-26.8701 113.7388,-26.8702 113.7388,-26.8702 113.7388,-26.8702 117.2388,-26.8701 113.7387,-23.7202 120.7388,-26.8701 120.7388,-26.8701\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-30.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;0 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>2&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M123.8943,-16.8C117.6932,-13.2382 110.2713,-9.6712 103,-7.8701 94.19,-5.6878 84.851,-8.3469 76.8389,-12.301\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"70.4615,-15.8492 75.047,-9.6932 73.52,-14.1475 76.5785,-12.4458 76.5785,-12.4458 76.5785,-12.4458 73.52,-14.1475 78.11,-15.1985 70.4615,-15.8492 70.4615,-15.8492\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-11.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"222\" cy=\"-26.8701\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-23.1701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;3 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>2&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M157.0098,-26.8701C168.5679,-26.8701 183.7507,-26.8701 196.5345,-26.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"203.7388,-26.8701 196.7388,-30.0202 200.2388,-26.8701 196.7388,-26.8702 196.7388,-26.8702 196.7388,-26.8702 200.2388,-26.8701 196.7387,-23.7202 203.7388,-26.8701 203.7388,-26.8701\"/>\n",
"<text text-anchor=\"start\" x=\"175\" y=\"-30.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"313.8701\" cy=\"-26.8701\" rx=\"26.7407\" ry=\"26.7407\"/>\n",
"<text text-anchor=\"start\" x=\"309.3701\" y=\"-30.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"<text text-anchor=\"start\" x=\"305.8701\" y=\"-15.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;3 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>1&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M290.4545,-13.3564C280.544,-9.2024 268.8106,-6.318 258,-8.8701 253.248,-9.9919 248.408,-11.8423 243.8821,-13.94\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"237.5228,-17.1343 242.3641,-11.1774 240.6505,-15.5633 243.7781,-13.9923 243.7781,-13.9923 243.7781,-13.9923 240.6505,-15.5633 245.192,-16.8071 237.5228,-17.1343 237.5228,-17.1343\"/>\n",
"<text text-anchor=\"start\" x=\"260\" y=\"-12.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;1 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>3&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M240.1506,-26.8701C251.3575,-26.8701 266.0987,-26.8701 279.452,-26.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"286.6963,-26.8701 279.6964,-30.0202 283.1963,-26.8701 279.6963,-26.8702 279.6963,-26.8702 279.6963,-26.8702 283.1963,-26.8701 279.6963,-23.7202 286.6963,-26.8701 286.6963,-26.8701\"/>\n",
"<text text-anchor=\"start\" x=\"258\" y=\"-30.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa244d50270> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"aut = spot.automaton('randaut --seed=30 -Q4 -A\"Fin(0)\" a |')\n",
"spot.highlight_stutter_invariant_states(aut, None, 5)\n",
"display(aut)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If the negated automaton is already known, it can be passed as second argument (instead of the positive formula) to avoid unnecessary work."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sutter-invariance at the letter level\n",
"\n",
"Instead of marking each state as stuttering or not, we can list the letters that we can stutter in each state.\n",
"More precisely, a state $q$ is _stutter-invariant for letter $a$_ if the membership to $L(q)$ of any word starting with $a$ is preserved by the operations that duplicate letters or remove duplicates. \n",
"\n",
"$(\\ell_0\\ldots\\ell_{i-1}\\ell_i\\ell_{i+1}\\ldots\\in L(q) \\land \\ell_0=a) \\iff (\\ell_0\\ldots\\ell_{i-1}\\ell_i\\ell_i\\ell_{i+1}\\ldots\\in L(q)\\land \\ell_0=a)$\n",
"\n",
"Under this definition, we can also say that $q$ is _stutter-invariant_ iff it is _stutter-invariant for any letter_.\n",
"\n",
"For instance consider the following automaton, for which all words that start with $b$ are stutter invariant.\n",
"The initial state may not be declared as stutter-invariant because of words that start with $\\lnot b$."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"281pt\" height=\"227pt\"\n",
" viewBox=\"0.00 0.00 281.48 226.74\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 222.7401)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-222.7401 277.4802,-222.7401 277.4802,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"115.7401\" y=\"-204.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"137.7401\" y=\"-204.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"153.7401\" y=\"-204.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"113.7401\" y=\"-190.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[Büchi]</text>\n",
"<!-- I -->\n",
"<!-- 3 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-74.8701\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-71.1701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- I&#45;&gt;3 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-74.8701C4.178,-74.8701 17.9448,-74.8701 30.9241,-74.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-74.8701 30.9808,-78.0202 34.4807,-74.8701 30.9807,-74.8702 30.9807,-74.8702 30.9807,-74.8702 34.4807,-74.8701 30.9807,-71.7202 37.9807,-74.8701 37.9807,-74.8701\"/>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"149.8701\" cy=\"-122.8701\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"149.8701\" y=\"-119.1701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;0 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>3&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M72.3509,-83.231C87.5611,-91.0087 110.3614,-102.6675 127.3016,-111.3298\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"133.7065,-114.6049 126.0399,-114.2225 130.5903,-113.0114 127.4741,-111.4179 127.4741,-111.4179 127.4741,-111.4179 130.5903,-113.0114 128.9082,-108.6133 133.7065,-114.6049 133.7065,-114.6049\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-102.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!b</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"149.8701\" cy=\"-26.8701\" rx=\"26.7407\" ry=\"26.7407\"/>\n",
"<text text-anchor=\"start\" x=\"145.3701\" y=\"-30.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"<text text-anchor=\"start\" x=\"141.8701\" y=\"-15.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;1 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>3&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M72.3509,-66.5091C85.2203,-59.9284 103.5234,-50.5692 119.1132,-42.5974\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"125.6046,-39.2781 120.8063,-45.2697 122.4884,-40.8716 119.3722,-42.465 119.3722,-42.465 119.3722,-42.465 122.4884,-40.8716 117.938,-39.6604 125.6046,-39.2781 125.6046,-39.2781\"/>\n",
"<text text-anchor=\"start\" x=\"94\" y=\"-59.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">b</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"246.6102\" cy=\"-122.8701\" rx=\"26.7407\" ry=\"26.7407\"/>\n",
"<text text-anchor=\"start\" x=\"242.1102\" y=\"-126.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"<text text-anchor=\"start\" x=\"238.6102\" y=\"-111.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;2 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M168.0661,-122.8701C180.5777,-122.8701 197.5739,-122.8701 212.5562,-122.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"219.7209,-122.8701 212.7209,-126.0202 216.2209,-122.8701 212.7209,-122.8702 212.7209,-122.8702 212.7209,-122.8702 216.2209,-122.8701 212.7208,-119.7202 219.7209,-122.8701 219.7209,-122.8701\"/>\n",
"<text text-anchor=\"start\" x=\"194.7401\" y=\"-126.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;2 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>2&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M237.6893,-148.2401C237.074,-158.7939 240.0477,-167.7401 246.6102,-167.7401 251.6346,-167.7401 254.5553,-162.496 255.3722,-155.3013\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"255.5311,-148.2401 258.5228,-155.3092 255.4523,-151.7392 255.3736,-155.2383 255.3736,-155.2383 255.3736,-155.2383 255.4523,-151.7392 252.2243,-155.1674 255.5311,-148.2401 255.5311,-148.2401\"/>\n",
"<text text-anchor=\"middle\" x=\"246.6102\" y=\"-171.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M140.9492,-52.2401C140.3339,-62.7939 143.3076,-71.7401 149.8701,-71.7401 154.8945,-71.7401 157.8152,-66.496 158.6321,-59.3013\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"158.791,-52.2401 161.7826,-59.3092 158.7122,-55.7392 158.6334,-59.2383 158.6334,-59.2383 158.6334,-59.2383 158.7122,-55.7392 155.4842,-59.1674 158.791,-52.2401 158.791,-52.2401\"/>\n",
"<text text-anchor=\"start\" x=\"145.3701\" y=\"-75.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">b</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa24446eb70> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"f = spot.formula('(!b&Xa) | Gb')\n",
"pos = spot.translate(f)\n",
"spot.highlight_stutter_invariant_states(pos, f, 5)\n",
"display(pos)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `stutter_invariant_letters()` functions returns a vector of BDDs indexed by state numbers. The BDD at index $q$ specifies all letters $\\ell$ for which state $q$ would be stuttering. Note that if $q$ is stutter-invariant or reachable from a stutter-invariant state, the associated BDD will be `bddtrue` (printed as `1` below).\n",
"\n",
"This interface is a bit inconveniant to use interactively, due to the fact that we need a `spot.bdd_dict` object to print a BDD."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"sil_vec[0] = 1\n",
"sil_vec[1] = 1\n",
"sil_vec[2] = 1\n",
"sil_vec[3] = b\n"
]
}
],
"source": [
"sil_vec = spot.stutter_invariant_letters(pos, f)\n",
"for q in range(pos.num_states()):\n",
" print(\"sil_vec[{}] =\".format(q), spot.bdd_format_formula(pos.get_dict(), sil_vec[q]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The set of stutter-invariant states is not always forward closed\n",
"\n",
"Consider the following automaton, which is a variant of our second example above. \n",
"\n",
"The language accepted from state (2) is `!GF(a & Xa) & GF!a` (this can be simplified to `FG(!a | X!a)`), while the language accepted from state (0) is `GF(a & Xa) & GF!a`. Therefore. the language accepted from state (5) is `a & X(GF!a)`. Since this is equivalent to `a & GF(!a)` state (5) recognizes stutter-invariant language, but as we can see, it is not the case that all states below (5) are also marked. In fact, states (0) can also be reached via states (7) and (6), recognizing respectively `(a & X(a & GF!a)) | (!a & X(!a & GF(a & Xa) & GF!a))` and `!a & GF(a & Xa) & GF!a))`, i.e., two stutter-sentive languages."
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"440pt\" height=\"291pt\"\n",
" viewBox=\"0.00 0.00 440.00 291.31\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 287.3113)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-287.3113 436,-287.3113 436,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"169\" y=\"-269.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"191\" y=\"-269.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"207\" y=\"-269.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)&amp;Inf(</text>\n",
"<text text-anchor=\"start\" x=\"243\" y=\"-269.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"<text text-anchor=\"start\" x=\"259\" y=\"-269.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"172\" y=\"-255.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[gen. Büchi 2]</text>\n",
"<!-- I -->\n",
"<!-- 7 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>7</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-46.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-42.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">7</text>\n",
"</g>\n",
"<!-- I&#45;&gt;7 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;7</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-46.3113C4.178,-46.3113 17.9448,-46.3113 30.9241,-46.3113\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-46.3113 30.9808,-49.4614 34.4807,-46.3113 30.9807,-46.3114 30.9807,-46.3114 30.9807,-46.3114 34.4807,-46.3113 30.9807,-43.1614 37.9807,-46.3113 37.9807,-46.3113\"/>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g id=\"node8\" class=\"node\">\n",
"<title>5</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"139\" cy=\"-73.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"139\" y=\"-69.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">5</text>\n",
"</g>\n",
"<!-- 7&#45;&gt;5 -->\n",
"<g id=\"edge17\" class=\"edge\">\n",
"<title>7&#45;&gt;5</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M73.1977,-51.9057C85.328,-55.8517 101.7356,-61.1891 115.132,-65.547\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"121.8244,-67.724 114.1933,-68.554 118.4961,-66.6413 115.1677,-65.5585 115.1677,-65.5585 115.1677,-65.5585 118.4961,-66.6413 116.1422,-62.563 121.8244,-67.724 121.8244,-67.724\"/>\n",
"<text text-anchor=\"start\" x=\"94\" y=\"-66.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g id=\"node9\" class=\"node\">\n",
"<title>6</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"139\" cy=\"-19.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"139\" y=\"-15.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">6</text>\n",
"</g>\n",
"<!-- 7&#45;&gt;6 -->\n",
"<g id=\"edge16\" class=\"edge\">\n",
"<title>7&#45;&gt;6</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M72.7216,-39.4036C78.7498,-37.0213 85.6352,-34.4231 92,-32.3113 99.2318,-29.9118 107.1878,-27.5926 114.4649,-25.594\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"121.4638,-23.711 115.5225,-28.5715 118.084,-24.6204 114.7041,-25.5297 114.7041,-25.5297 114.7041,-25.5297 118.084,-24.6204 113.8857,-22.4878 121.4638,-23.711 121.4638,-23.711\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-36.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"222\" cy=\"-19.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-15.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M218.4047,-37.093C217.7938,-46.6262 218.9922,-55.3113 222,-55.3113 224.2089,-55.3113 225.4419,-50.6274 225.6991,-44.3634\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"225.5953,-37.093 228.845,-44.0472 225.6453,-40.5926 225.6954,-44.0923 225.6954,-44.0923 225.6954,-44.0923 225.6453,-40.5926 222.5457,-44.1373 225.5953,-37.093 225.5953,-37.093\"/>\n",
"<text text-anchor=\"start\" x=\"216.5\" y=\"-74.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"214\" y=\"-59.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M216.494,-36.5603C212.5865,-57.7458 214.4219,-85.3113 222,-85.3113 228.7493,-85.3113 230.9433,-63.446 228.582,-43.6964\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"227.506,-36.5603 231.6646,-43.0123 228.0279,-40.0212 228.5498,-43.482 228.5498,-43.482 228.5498,-43.482 228.0279,-40.0212 225.435,-43.9518 227.506,-36.5603 227.506,-36.5603\"/>\n",
"<text text-anchor=\"start\" x=\"218.5\" y=\"-89.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"310\" cy=\"-21.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"310\" y=\"-17.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M240.2337,-19.7257C253.0948,-20.018 270.4907,-20.4133 284.6942,-20.7361\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"291.7897,-20.8974 284.7199,-23.8874 288.2906,-20.8178 284.7915,-20.7382 284.7915,-20.7382 284.7915,-20.7382 288.2906,-20.8178 284.8631,-17.5891 291.7897,-20.8974 291.7897,-20.8974\"/>\n",
"<text text-anchor=\"start\" x=\"262.5\" y=\"-40.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"258\" y=\"-25.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M294.9614,-10.7166C288.7695,-6.968 281.3364,-3.2123 274,-1.3113 263.8793,1.3113 252.9087,-1.5979 243.6644,-5.7885\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"237.2751,-9.0056 242.1106,-3.044 240.4012,-7.4316 243.5273,-5.8575 243.5273,-5.8575 243.5273,-5.8575 240.4012,-7.4316 244.9439,-8.671 237.2751,-9.0056 237.2751,-9.0056\"/>\n",
"<text text-anchor=\"start\" x=\"262.5\" y=\"-5.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M302.3321,-37.6015C300.4831,-47.7004 303.0391,-57.3113 310,-57.3113 315.2207,-57.3113 317.9636,-51.9052 318.2287,-44.9417\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"317.6679,-37.6015 321.3421,-44.3412 317.9346,-41.0914 318.2013,-44.5812 318.2013,-44.5812 318.2013,-44.5812 317.9346,-41.0914 315.0604,-44.8212 317.6679,-37.6015 317.6679,-37.6015\"/>\n",
"<text text-anchor=\"start\" x=\"306.5\" y=\"-76.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"302\" y=\"-61.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"222\" cy=\"-154.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-150.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;2 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>2&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M214.9688,-170.9753C213.4063,-180.9363 215.75,-190.3113 222,-190.3113 226.6875,-190.3113 229.1777,-185.0378 229.4707,-178.1988\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"229.0313,-170.9753 232.6006,-177.7711 229.2438,-174.4689 229.4564,-177.9624 229.4564,-177.9624 229.4564,-177.9624 229.2438,-174.4689 226.3122,-178.1537 229.0313,-170.9753 229.0313,-170.9753\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-194.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g id=\"node6\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"310\" cy=\"-183.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"310\" y=\"-179.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;3 -->\n",
"<g id=\"edge8\" class=\"edge\">\n",
"<title>2&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M239.386,-160.0407C252.6441,-164.4099 271.0661,-170.4808 285.7697,-175.3263\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"292.6501,-177.5937 285.0159,-178.3945 289.326,-176.4982 286.0018,-175.4027 286.0018,-175.4027 286.0018,-175.4027 289.326,-176.4982 286.9878,-172.411 292.6501,-177.5937 292.6501,-177.5937\"/>\n",
"<text text-anchor=\"start\" x=\"260.5\" y=\"-175.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g id=\"node7\" class=\"node\">\n",
"<title>4</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"414\" cy=\"-165.3113\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"414\" y=\"-161.6113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">4</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;4 -->\n",
"<g id=\"edge9\" class=\"edge\">\n",
"<title>2&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M239.7121,-150.0898C253.7887,-146.9615 274.0296,-142.9658 292,-141.3113 307.9326,-139.8443 312.1479,-139.1408 328,-141.3113 349.3665,-144.2367 372.9092,-151.0708 389.9522,-156.7011\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"396.8331,-159.0254 389.1931,-159.7695 393.5172,-157.9053 390.2013,-156.7851 390.2013,-156.7851 390.2013,-156.7851 393.5172,-157.9053 391.2094,-153.8008 396.8331,-159.0254 396.8331,-159.0254\"/>\n",
"<text text-anchor=\"start\" x=\"306.5\" y=\"-145.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;3 -->\n",
"<g id=\"edge10\" class=\"edge\">\n",
"<title>3&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M302.3321,-199.6015C300.4831,-209.7004 303.0391,-219.3113 310,-219.3113 315.2207,-219.3113 317.9636,-213.9052 318.2287,-206.9417\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"317.6679,-199.6015 321.3421,-206.3412 317.9346,-203.0914 318.2013,-206.5812 318.2013,-206.5812 318.2013,-206.5812 317.9346,-203.0914 315.0604,-206.8212 317.6679,-199.6015 317.6679,-199.6015\"/>\n",
"<text text-anchor=\"start\" x=\"304.5\" y=\"-237.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"294\" y=\"-223.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"310\" y=\"-223.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g id=\"edge11\" class=\"edge\">\n",
"<title>3&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M325.5974,-174.1666C331.7433,-171.0459 338.9976,-167.9356 346,-166.3113 359.8448,-163.0996 375.7045,-162.6872 388.6231,-163.1516\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"395.852,-163.5119 388.7039,-166.3095 392.3564,-163.3376 388.8607,-163.1634 388.8607,-163.1634 388.8607,-163.1634 392.3564,-163.3376 389.0175,-160.0173 395.852,-163.5119 395.852,-163.5119\"/>\n",
"<text text-anchor=\"start\" x=\"358.5\" y=\"-184.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"346\" y=\"-170.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"362\" y=\"-170.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;3 -->\n",
"<g id=\"edge12\" class=\"edge\">\n",
"<title>4&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M401.6807,-178.7611C395.2775,-184.7539 386.9311,-191.1615 378,-194.3113 363.7261,-199.3454 346.9455,-196.7133 333.6255,-192.7648\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"326.6194,-190.476 334.2516,-189.6555 329.9464,-191.5629 333.2734,-192.6498 333.2734,-192.6498 333.2734,-192.6498 329.9464,-191.5629 332.2952,-195.6441 326.6194,-190.476 326.6194,-190.476\"/>\n",
"<text text-anchor=\"start\" x=\"356.5\" y=\"-214.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"346\" y=\"-200.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"362\" y=\"-200.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;0 -->\n",
"<g id=\"edge13\" class=\"edge\">\n",
"<title>5&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M154.2235,-63.4068C167.3274,-54.8814 186.369,-42.4929 200.9349,-33.0163\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"206.873,-29.1529 202.7234,-35.6107 203.9393,-31.0616 201.0055,-32.9704 201.0055,-32.9704 201.0055,-32.9704 203.9393,-31.0616 199.2877,-30.33 206.873,-29.1529 206.873,-29.1529\"/>\n",
"<text text-anchor=\"start\" x=\"177\" y=\"-54.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;2 -->\n",
"<g id=\"edge14\" class=\"edge\">\n",
"<title>5&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M151.9688,-85.9675C165.8961,-99.5592 188.1327,-121.26 203.8061,-136.5558\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"208.8484,-141.4766 201.6386,-138.8419 206.3435,-139.032 203.8386,-136.5875 203.8386,-136.5875 203.8386,-136.5875 206.3435,-139.032 206.0387,-134.3331 208.8484,-141.4766 208.8484,-141.4766\"/>\n",
"<text text-anchor=\"start\" x=\"177\" y=\"-122.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;0 -->\n",
"<g id=\"edge15\" class=\"edge\">\n",
"<title>6&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M157.0098,-19.3113C168.5679,-19.3113 183.7507,-19.3113 196.5345,-19.3113\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"203.7388,-19.3113 196.7388,-22.4614 200.2388,-19.3113 196.7388,-19.3114 196.7388,-19.3114 196.7388,-19.3114 200.2388,-19.3113 196.7387,-16.1614 203.7388,-19.3113 203.7388,-19.3113\"/>\n",
"<text text-anchor=\"start\" x=\"175\" y=\"-23.1113\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa244480540> >"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ex1 = spot.automaton(\"\"\"HOA: v1 \n",
"States: 8 Start: 7 AP: 1 \"a\" Acceptance: 2 (Inf(0)&Inf(1))\n",
"--BODY--\n",
"State: 0 [!0] 0 {1} [0] 0 [0] 1 {0}\n",
"State: 1 [0] 0 [0] 1 {0}\n",
"State: 2 [t] 2 [!0] 3 [0] 4\n",
"State: 3 [!0] 3 {0 1} [0] 4 {0 1}\n",
"State: 4 [!0] 3 {0 1}\n",
"State: 5 [0] 0 [0] 2\n",
"State: 6 [!0] 0\n",
"State: 7 [!0] 6 [0] 5\n",
"--END--\"\"\")\n",
"spot.highlight_stutter_invariant_states(ex1,None, 5)\n",
"display(ex1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This situation can be tested with `spot.is_stutter_invariant_forward_closed()`. The function returns `-1` if the successor of any stutter-invariant state is it is also a stutter-invariant state, otherwise it return the number of one stutter-sensitive state that has a stutter-invariant state as predecessor."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sistates = spot.stutter_invariant_states(ex1)\n",
"spot.is_stutter_invariant_forward_closed(ex1, sistates)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In cases where we prefer to have a forward-closed set of stutter-invariant states, it is always possible to duplicate\n",
"the problematic states. The `make_stutter_invariant_foward_closed_inplace()` modifies the automaton in place, and also returns an updated copie of the vector of stutter-invariant states."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"389pt\" height=\"360pt\"\n",
" viewBox=\"0.00 0.00 389.19 360.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(.8845 .8845) rotate(0) translate(4 403)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-403 436,-403 436,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"169\" y=\"-384.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">Inf(</text>\n",
"<text text-anchor=\"start\" x=\"191\" y=\"-384.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"207\" y=\"-384.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)&amp;Inf(</text>\n",
"<text text-anchor=\"start\" x=\"243\" y=\"-384.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"<text text-anchor=\"start\" x=\"259\" y=\"-384.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">)</text>\n",
"<text text-anchor=\"start\" x=\"172\" y=\"-370.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[gen. Büchi 2]</text>\n",
"<!-- I -->\n",
"<!-- 7 -->\n",
"<g id=\"node2\" class=\"node\">\n",
"<title>7</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"56\" cy=\"-108\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-104.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">7</text>\n",
"</g>\n",
"<!-- I&#45;&gt;7 -->\n",
"<g id=\"edge1\" class=\"edge\">\n",
"<title>I&#45;&gt;7</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1233,-108C4.178,-108 17.9448,-108 30.9241,-108\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"37.9807,-108 30.9808,-111.1501 34.4807,-108 30.9807,-108.0001 30.9807,-108.0001 30.9807,-108.0001 34.4807,-108 30.9807,-104.8501 37.9807,-108 37.9807,-108\"/>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g id=\"node8\" class=\"node\">\n",
"<title>5</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"139\" cy=\"-155\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"139\" y=\"-151.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">5</text>\n",
"</g>\n",
"<!-- 7&#45;&gt;5 -->\n",
"<g id=\"edge17\" class=\"edge\">\n",
"<title>7&#45;&gt;5</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M72.0032,-117.0621C84.8304,-124.3256 102.9633,-134.5937 117.1305,-142.6161\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"123.3274,-146.1251 115.684,-145.4169 120.2818,-144.4005 117.2362,-142.6759 117.2362,-142.6759 117.2362,-142.6759 120.2818,-144.4005 118.7883,-139.9348 123.3274,-146.1251 123.3274,-146.1251\"/>\n",
"<text text-anchor=\"start\" x=\"94\" y=\"-138.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g id=\"node10\" class=\"node\">\n",
"<title>6</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"139\" cy=\"-81\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"139\" y=\"-77.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">6</text>\n",
"</g>\n",
"<!-- 7&#45;&gt;6 -->\n",
"<g id=\"edge16\" class=\"edge\">\n",
"<title>7&#45;&gt;6</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M72.7216,-101.0924C78.7498,-98.71 85.6352,-96.1118 92,-94 99.2318,-91.6005 107.1878,-89.2814 114.4649,-87.2827\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"121.4638,-85.3998 115.5225,-90.2603 118.084,-86.3091 114.7041,-87.2184 114.7041,-87.2184 114.7041,-87.2184 118.084,-86.3091 113.8857,-84.1766 121.4638,-85.3998 121.4638,-85.3998\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-97.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"222\" cy=\"-20\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-16.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">0</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M218.4047,-37.7817C217.7938,-47.3149 218.9922,-56 222,-56 224.2089,-56 225.4419,-51.3161 225.6991,-45.0521\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"225.5953,-37.7817 228.845,-44.736 225.6453,-41.2814 225.6954,-44.781 225.6954,-44.781 225.6954,-44.781 225.6453,-41.2814 222.5457,-44.8261 225.5953,-37.7817 225.5953,-37.7817\"/>\n",
"<text text-anchor=\"start\" x=\"216.5\" y=\"-74.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"214\" y=\"-59.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\">\n",
"<title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M216.494,-37.249C212.5865,-58.4346 214.4219,-86 222,-86 228.7493,-86 230.9433,-64.1347 228.582,-44.3851\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"227.506,-37.249 231.6646,-43.7011 228.0279,-40.7099 228.5498,-44.1708 228.5498,-44.1708 228.5498,-44.1708 228.0279,-40.7099 225.435,-44.6405 227.506,-37.249 227.506,-37.249\"/>\n",
"<text text-anchor=\"start\" x=\"218.5\" y=\"-89.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node4\" class=\"node\">\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"310\" cy=\"-18\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"310\" y=\"-14.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M239.8095,-23.4062C249.8505,-24.9015 262.6252,-26.0956 274,-25 277.6303,-24.6503 281.4384,-24.1067 285.163,-23.4733\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"292.1538,-22.1724 285.8483,-26.55 288.7129,-22.8128 285.272,-23.4531 285.272,-23.4531 285.272,-23.4531 288.7129,-22.8128 284.6956,-20.3563 292.1538,-22.1724 292.1538,-22.1724\"/>\n",
"<text text-anchor=\"start\" x=\"262.5\" y=\"-44.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"258\" y=\"-29.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge5\" class=\"edge\">\n",
"<title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M293.2126,-10.5266C283.0625,-6.9084 269.838,-3.7792 258,-6 253.7776,-6.7921 249.4141,-8.0645 245.2445,-9.5272\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"238.4696,-12.1172 243.8832,-6.6752 241.7388,-10.8674 245.0081,-9.6175 245.0081,-9.6175 245.0081,-9.6175 241.7388,-10.8674 246.1329,-12.5598 238.4696,-12.1172 238.4696,-12.1172\"/>\n",
"<text text-anchor=\"start\" x=\"262.5\" y=\"-9.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge6\" class=\"edge\">\n",
"<title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M302.3321,-34.2903C300.4831,-44.3892 303.0391,-54 310,-54 315.2207,-54 317.9636,-48.5939 318.2287,-41.6304\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"317.6679,-34.2903 321.3421,-41.0299 317.9346,-37.7801 318.2013,-41.2699 318.2013,-41.2699 318.2013,-41.2699 317.9346,-37.7801 315.0604,-41.5099 317.6679,-34.2903 317.6679,-34.2903\"/>\n",
"<text text-anchor=\"start\" x=\"306.5\" y=\"-72.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"302\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g id=\"node5\" class=\"node\">\n",
"<title>2</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"222\" cy=\"-290\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-286.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">2</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;2 -->\n",
"<g id=\"edge7\" class=\"edge\">\n",
"<title>2&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M214.9688,-306.6641C213.4063,-316.625 215.75,-326 222,-326 226.6875,-326 229.1777,-320.7266 229.4707,-313.8876\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"229.0313,-306.6641 232.6006,-313.4598 229.2438,-310.1576 229.4564,-313.6511 229.4564,-313.6511 229.4564,-313.6511 229.2438,-310.1576 226.3122,-313.8425 229.0313,-306.6641 229.0313,-306.6641\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-329.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">1</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g id=\"node6\" class=\"node\">\n",
"<title>3</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"310\" cy=\"-299\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"310\" y=\"-295.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">3</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;3 -->\n",
"<g id=\"edge8\" class=\"edge\">\n",
"<title>2&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M240.2337,-291.8648C253.1805,-293.1889 270.7229,-294.983 284.9778,-296.4409\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"292.0908,-297.1684 284.8066,-299.5897 288.609,-296.8122 285.1271,-296.4561 285.1271,-296.4561 285.1271,-296.4561 288.609,-296.8122 285.4476,-293.3224 292.0908,-297.1684 292.0908,-297.1684\"/>\n",
"<text text-anchor=\"start\" x=\"260.5\" y=\"-298.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g id=\"node7\" class=\"node\">\n",
"<title>4</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"414\" cy=\"-281\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"414\" y=\"-277.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">4</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;4 -->\n",
"<g id=\"edge9\" class=\"edge\">\n",
"<title>2&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M237.4046,-280.2954C251.1303,-272.2591 272.0714,-261.462 292,-257 326.2734,-249.3263 366.2613,-261.1012 390.8558,-270.7029\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"397.3669,-273.3355 389.6965,-273.6319 394.1221,-272.0236 390.8773,-270.7116 390.8773,-270.7116 390.8773,-270.7116 394.1221,-272.0236 392.0581,-267.7913 397.3669,-273.3355 397.3669,-273.3355\"/>\n",
"<text text-anchor=\"start\" x=\"306.5\" y=\"-260.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;3 -->\n",
"<g id=\"edge10\" class=\"edge\">\n",
"<title>3&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M302.3321,-315.2903C300.4831,-325.3892 303.0391,-335 310,-335 315.2207,-335 317.9636,-329.5939 318.2287,-322.6304\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"317.6679,-315.2903 321.3421,-322.0299 317.9346,-318.7801 318.2013,-322.2699 318.2013,-322.2699 318.2013,-322.2699 317.9346,-318.7801 315.0604,-322.5099 317.6679,-315.2903 317.6679,-315.2903\"/>\n",
"<text text-anchor=\"start\" x=\"304.5\" y=\"-352.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"294\" y=\"-338.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"310\" y=\"-338.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g id=\"edge11\" class=\"edge\">\n",
"<title>3&#45;&gt;4</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M326.6194,-306.1648C340.6445,-311.1643 361.0827,-315.9664 378,-310 384.5588,-307.6869 390.8022,-303.6168 396.1923,-299.2443\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"401.6807,-294.4499 398.4813,-301.4275 399.0448,-296.7525 396.4089,-299.0551 396.4089,-299.0551 396.4089,-299.0551 399.0448,-296.7525 394.3365,-296.6828 401.6807,-294.4499 401.6807,-294.4499\"/>\n",
"<text text-anchor=\"start\" x=\"358.5\" y=\"-329.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"346\" y=\"-315.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"362\" y=\"-315.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;3 -->\n",
"<g id=\"edge12\" class=\"edge\">\n",
"<title>4&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M396.3497,-277.3203C382.4303,-275.1063 362.655,-273.4973 346,-278 340.8137,-279.4021 335.6075,-281.7575 330.8291,-284.3951\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"324.6205,-288.104 329.0145,-281.8099 327.6252,-286.3091 330.6299,-284.5141 330.6299,-284.5141 330.6299,-284.5141 327.6252,-286.3091 332.2454,-287.2184 324.6205,-288.104 324.6205,-288.104\"/>\n",
"<text text-anchor=\"start\" x=\"356.5\" y=\"-295.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"346\" y=\"-281.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"<text text-anchor=\"start\" x=\"362\" y=\"-281.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;2 -->\n",
"<g id=\"edge14\" class=\"edge\">\n",
"<title>5&#45;&gt;2</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M148.2468,-170.8793C160.652,-192.0617 183.4987,-230.6526 204,-263 205.2365,-264.951 206.5386,-266.9696 207.8537,-268.9841\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"211.7847,-274.9437 205.3008,-270.8349 209.8575,-272.0221 207.9303,-269.1004 207.9303,-269.1004 207.9303,-269.1004 209.8575,-272.0221 210.5598,-267.366 211.7847,-274.9437 211.7847,-274.9437\"/>\n",
"<text text-anchor=\"start\" x=\"177\" y=\"-236.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 8 -->\n",
"<g id=\"node9\" class=\"node\">\n",
"<title>8</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"222\" cy=\"-155\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"222\" y=\"-151.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">8</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;8 -->\n",
"<g id=\"edge13\" class=\"edge\">\n",
"<title>5&#45;&gt;8</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M157.0098,-155C168.5679,-155 183.7507,-155 196.5345,-155\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"203.7388,-155 196.7388,-158.1501 200.2388,-155 196.7388,-155.0001 196.7388,-155.0001 196.7388,-155.0001 200.2388,-155 196.7387,-151.8501 203.7388,-155 203.7388,-155\"/>\n",
"<text text-anchor=\"start\" x=\"177\" y=\"-158.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 8&#45;&gt;8 -->\n",
"<g id=\"edge18\" class=\"edge\">\n",
"<title>8&#45;&gt;8</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M218.4047,-172.7817C217.7938,-182.3149 218.9922,-191 222,-191 224.2089,-191 225.4419,-186.3161 225.6991,-180.0521\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"225.5953,-172.7817 228.845,-179.736 225.6453,-176.2814 225.6954,-179.781 225.6954,-179.781 225.6954,-179.781 225.6453,-176.2814 222.5457,-179.8261 225.5953,-172.7817 225.5953,-172.7817\"/>\n",
"<text text-anchor=\"start\" x=\"216.5\" y=\"-209.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"<text text-anchor=\"start\" x=\"214\" y=\"-194.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#ff4da0\">❶</text>\n",
"</g>\n",
"<!-- 8&#45;&gt;8 -->\n",
"<g id=\"edge19\" class=\"edge\">\n",
"<title>8&#45;&gt;8</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M216.494,-172.249C212.5865,-193.4346 214.4219,-221 222,-221 228.7493,-221 230.9433,-199.1347 228.582,-179.3851\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"227.506,-172.249 231.6646,-178.7011 228.0279,-175.7099 228.5498,-179.1708 228.5498,-179.1708 228.5498,-179.1708 228.0279,-175.7099 225.435,-179.6405 227.506,-172.249 227.506,-172.249\"/>\n",
"<text text-anchor=\"start\" x=\"218.5\" y=\"-224.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 9 -->\n",
"<g id=\"node11\" class=\"node\">\n",
"<title>9</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#e31a1c\" stroke-width=\"2\" cx=\"310\" cy=\"-137\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"310\" y=\"-133.3\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">9</text>\n",
"</g>\n",
"<!-- 8&#45;&gt;9 -->\n",
"<g id=\"edge20\" class=\"edge\">\n",
"<title>8&#45;&gt;9</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M239.8081,-151.3574C252.8094,-148.6981 270.6078,-145.0575 285.0285,-142.1078\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"292.2184,-140.6372 285.9916,-145.1261 288.7894,-141.3386 285.3604,-142.04 285.3604,-142.04 285.3604,-142.04 288.7894,-141.3386 284.7291,-138.9539 292.2184,-140.6372 292.2184,-140.6372\"/>\n",
"<text text-anchor=\"start\" x=\"262.5\" y=\"-166.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"258\" y=\"-151.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;0 -->\n",
"<g id=\"edge15\" class=\"edge\">\n",
"<title>6&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M153.8387,-70.0944C167.0579,-60.3791 186.5358,-46.064 201.2885,-35.2217\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"207.2897,-30.8112 203.5147,-37.4949 204.4695,-32.8839 201.6492,-34.9566 201.6492,-34.9566 201.6492,-34.9566 204.4695,-32.8839 199.7837,-32.4184 207.2897,-30.8112 207.2897,-30.8112\"/>\n",
"<text text-anchor=\"start\" x=\"175\" y=\"-58.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!a</text>\n",
"</g>\n",
"<!-- 9&#45;&gt;8 -->\n",
"<g id=\"edge21\" class=\"edge\">\n",
"<title>9&#45;&gt;8</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M293.7718,-129.0844C283.3617,-125.0941 269.661,-121.8874 258,-126 251.4412,-128.3131 245.1978,-132.3832 239.8077,-136.7557\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"234.3193,-141.5501 237.5187,-134.5725 236.9552,-139.2475 239.5911,-136.9449 239.5911,-136.9449 239.5911,-136.9449 236.9552,-139.2475 241.6635,-139.3172 234.3193,-141.5501 234.3193,-141.5501\"/>\n",
"<text text-anchor=\"start\" x=\"262.5\" y=\"-129.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"</g>\n",
"<!-- 9&#45;&gt;9 -->\n",
"<g id=\"edge22\" class=\"edge\">\n",
"<title>9&#45;&gt;9</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M302.3321,-153.2903C300.4831,-163.3892 303.0391,-173 310,-173 315.2207,-173 317.9636,-167.5939 318.2287,-160.6304\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"317.6679,-153.2903 321.3421,-160.0299 317.9346,-156.7801 318.2013,-160.2699 318.2013,-160.2699 318.2013,-160.2699 317.9346,-156.7801 315.0604,-160.5099 317.6679,-153.2903 317.6679,-153.2903\"/>\n",
"<text text-anchor=\"start\" x=\"306.5\" y=\"-191.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a</text>\n",
"<text text-anchor=\"start\" x=\"302\" y=\"-176.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#1f78b4\">⓿</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fa244480540> >"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"(False, False, True, True, True, True, False, False, True, True)\n"
]
}
],
"source": [
"sistates2 = spot.make_stutter_invariant_forward_closed_inplace(ex1, sistates)\n",
"spot.highlight_stutter_invariant_states(ex1, None, 5)\n",
"display(ex1)\n",
"print(sistates2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, state 0 is no longuer a problem."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"-1"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"spot.is_stutter_invariant_forward_closed(ex1, sistates2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's see how infrequently the set of stutter-invarant states is not closed."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"import spot.gen as gen"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"formula states SIstates fwd_closed\n",
"(p1 & X(!p0 U p2)) R !p0 3 2 1\n",
"(!p1 U (p0 | (!p1 & p2 & X(!p1 U p3)))) 4 3 1\n",
"!p0 | ((p2 & X(!p1 U p3)) R !p1) 4 2 1\n",
"G(!p0 | (!p2 U (p1 | (!p2 & p3 & X(!p2 U 4 1 1\n",
"G(!p0 | (!p1 W (p2 | (!p1 & p3 & X(!p1 U 3 0 1\n",
"(!p0 U p2) | G(!p0 | XG!p1) 3 2 1\n",
"G!p0 | ((p0 | !p1 | X(!p2 W p0)) U (p0 | 4 3 1\n",
"!p0 W (p0 & ((!p1 U p3) | G(!p1 | XG!p2) 4 2 1\n",
"G(!p0 | G!p1 | ((p1 | !p2 | X(!p3 W p1)) 4 1 1\n",
"G(!p0 | ((p1 | !p2 | X(!p3 W p1)) U (p1 3 0 1\n",
"G(!p0 | X(F(p1 & Fp2) | G!p1)) 6 1 1\n",
"G!p0 | ((!p1 | X((!p0 U (p2 & Fp3)) | (p 6 2 1\n",
"G(!p0 | G(!p1 | X(!p2 W (p2 & Fp3)))) 5 0 1\n",
"G(!p0 | G!p1 | ((!p2 | X((!p1 U (p3 & Fp 10 2 1\n",
"G(!p0 | ((!p1 | X((!p2 U (p3 & Fp4)) | ( 10 0 1\n",
"G(!p0 | F(p1 & XFp2)) 4 0 1\n",
"G!p0 | ((!p1 | ((p2 & X(!p0 U p3)) M !p0 4 1 1\n",
"G(!p0 | G(!p1 | (p2 & XFp3))) 3 3 1\n",
"G(!p0 | G!p1 | ((!p2 | ((p3 & X(!p1 U p4 4 0 1\n",
"G(!p0 | ((!p1 | ((p3 & X(!p2 U p4)) M !p 6 2 1\n",
"G(!p0 | F(p1 & !p2 & X(!p2 U p3))) 4 0 1\n",
"G!p0 | ((!p1 | ((p2 & !p3 & X((!p0 & !p3 4 1 1\n",
"G(!p0 | G(!p1 | (p2 & !p3 & X(!p3 U p4)) 3 3 1\n",
"G(!p0 | G!p1 | ((!p2 | ((p3 & !p4 & X((! 4 0 1\n",
"G(!p0 | ((!p1 | ((p3 & !p4 & X((!p2 & !p 6 2 1\n",
"p0 U (p1 & X(p2 U p3)) 3 2 1\n",
"p0 U (p1 & X(p2 & F(p3 & XF(p4 & XF(p5 & 7 2 1\n",
"F(p0 & XGp1) 2 2 1\n",
"F(p0 & X(p1 & XFp2)) 4 2 1\n",
"F(p0 & X(p1 U p2)) 3 1 1\n",
"G(p0 & Fp1 & Fp2 & Fp3) 1 1 1\n",
"GF((!p0 & Xp0) | (p0 & X!p0) | (!p1 & Xp 4 4 1\n",
"GF((!p0 & Xp0) | (p0 & X!p0) | (!p1 & Xp 9 9 1\n",
"G(!p0 | !p1 | p2 | X(!p2 | p3 | X(!p1 | 3 0 1\n",
"G(!p0 | !p1 | p2 | X(!p2 | (p2 U (!p2 U 5 5 1\n",
"1 1 1 1\n",
"G(p0 | !p1 | Xp2) 2 0 1\n",
"G(!p0 | X(p0 | p1)) 2 2 1\n",
"G((((p1 & Xp1) | (!p1 & X!p1)) & ((p0 & 34 34 1\n",
"G(!p0 | p1 | !p2 | X(!p0 | !p1 | p3)) 2 2 1\n",
"G(!p0 | X(!p0 U p1)) 2 0 1\n",
"G(p0 | X(!p0 | (p0 W p1))) 3 3 1\n",
"G(p0 | X(!p0 | ((!p1 & X(p0 & p1)) M p0) 4 4 1\n",
"G(p0 | X(!p0 | ((!p1 & X(p1 & ((!p1 & X( 6 6 1\n",
"G(!p0 | X(p0 | ((!p1 & X(p1 & ((!p1 & X( 6 6 1\n",
"G(!p0 | X(p0 | ((!p1 & X(p1 & ((!p1 & X( 8 8 1\n",
"G(p0 | X(!p0 | ((p0 | X!p0) U (!p1 & Xp1 6 6 1\n",
"G(!p0 | X(!p0 | X(!p0 | X(!p0 | X(!p0 | 12 0 1\n",
"G((!p0 & Xp0) | (p1 & Xp1) | (!p1 & X!p1 4 4 1\n",
"G((!p0 & Xp0) | ((!p1 | Xp1) & (p1 | X!p 4 4 1\n",
"p0 & XG!p0 2 1 1\n",
"XG(!p0 | p2 | G!p1 | X(p2 M !p1)) 4 1 1\n",
"XG(!p0 | p1 | (!p1 W p2)) 3 2 1\n",
"XG(!p0 | !p1 | (p1 W p2)) 3 2 1\n",
"Xp0 & G(p0 | X(!p0 | Xp0)) 5 0 1\n",
"1 1 1 1\n",
"1 1 1 1\n",
"G(!p0 | Fp1) 2 2 1\n",
"G(!p0 | Fp1) 2 2 1\n",
"F(p0 & X(!p1 U !p2)) 3 1 1\n",
"(p0 & Xp1) R X(p2 R p0) 5 3 1\n",
"G((p0 | XGp1) & (p2 | XG!p1)) 3 2 1\n",
"Gp0 1 1 1\n"
]
}
],
"source": [
"# Let's consider the LTL formula from the following 5 sources,\n",
"# and restrict ourselves to formulas that are not stutter-invariant.\n",
"formulas = [ f for f in gen.ltl_patterns(gen.LTL_DAC_PATTERNS, \n",
" gen.LTL_EH_PATTERNS, \n",
" gen.LTL_HKRSS_PATTERNS, \n",
" gen.LTL_P_PATTERNS, \n",
" gen.LTL_SB_PATTERNS)\n",
" if not f.is_syntactic_stutter_invariant() ]\n",
"\n",
"aut_size = []\n",
"sistates_size = []\n",
"fwd_closed = []\n",
"\n",
"fmt = \"{:40.40} {:>6} {:>8} {:>10}\"\n",
"print(fmt.format(\"formula\", \"states\", \"SIstates\", \"fwd_closed\"))\n",
"for f in formulas:\n",
" aut = spot.translate(f)\n",
" aut_size.append(aut.num_states())\n",
" sistates = spot.stutter_invariant_states(aut, f)\n",
" sisz = sum(sistates)\n",
" sistates_size.append(sisz)\n",
" fc = spot.is_stutter_invariant_forward_closed(aut, sistates) == -1\n",
" fwd_closed.append(fc)\n",
" print(fmt.format(f.to_str(), aut.num_states(), sisz, fc))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There is no instance of set of stutter-invariant states that is not closed in these example formulas."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(63, 63)"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sum(fwd_closed), len(fwd_closed)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here is the percentage of stutter-invarant states."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"55.749128919860624"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"100*sum(sistates_size)/sum(aut_size)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}