{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Handling LTL and PSL formulas\n",
    "============================="
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import spot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For interactive use, formulas can be entered as text strings and passed to the `spot.formula` constructor."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))$"
      ],
      "text/plain": [
       "p1 U (p2 R (p3 & !p4))"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = spot.formula('p1 U p2 R (p3 & !p4)')\n",
    "f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\{a \\mathbin{\\mathsf{;}} b^{\\star} \\mathbin{\\mathsf{;}} c^+\\}\\mathrel{\\Diamond\\kern-1.7pt\\raise.4pt\\hbox{$\\mathord{\\rightarrow}$}} \\mathsf{G} \\mathsf{F} b$"
      ],
      "text/plain": [
       "{a;b[*];c[+]}<>-> GFb"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g = spot.formula('{a;b*;c[+]}<>->GFb'); g"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default the parser recognizes an infix syntax, but when this fails, it tries to read the formula with the [LBT](http://www.tcs.hut.fi/Software/maria/tools/lbt/) syntax:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$c \\land (a \\lor b)$"
      ],
      "text/plain": [
       "c & (a | b)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "h = spot.formula('& | a b c'); h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Passing a `formula` to `spot.formula` simply returns the formula."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$c \\land (a \\lor b)$"
      ],
      "text/plain": [
       "c & (a | b)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.formula(h)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, a formula object is presented using mathjax as above.\n",
    "When a formula is converted to string you get Spot's syntax by default:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'p1 U (p2 R (p3 & !p4))'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "str(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you prefer to print the string in another syntax, you may use the `to_str()` method, with an argument that indicates the output format to use.  The `latex` format assumes that you will the define macros such as `\\U`, `\\R` to render all operators as you wish.  On the otherhand, the `sclatex` (with `sc` for self-contained) format hard-codes the rendering of each of those operators: this is almost the same output that is used to render formulas using MathJax in a notebook. `sclatex` and `mathjax` only differ in the rendering of double-quoted atomic propositions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "spot      p1 U (p2 R (p3 & !p4))\n",
      "spin      p1 U (p2 V (p3 && !p4))\n",
      "lbt       U p1 V p2 & p3 ! p4\n",
      "wring     (p1=1) U ((p2=1) R ((p3=1) * (p4=0)))\n",
      "utf8      p1 U (p2 R (p3∧¬p4))\n",
      "latex     p_{1} \\U (p_{2} \\R (p_{3} \\land \\lnot p_{4}))\n",
      "sclatex   p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))\n",
      "mathjax   p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))\n"
     ]
    }
   ],
   "source": [
    "for i in ['spot', 'spin', 'lbt', 'wring', 'utf8', 'latex', 'sclatex', 'mathjax']:\n",
    "    print(\"%-10s%s\" % (i, f.to_str(i)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Formulas output via `format()` can also use some convenient shorthand to select the syntax:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spin:               p1 U (p2 V (p3 && !p4))\n",
      "Spin+parentheses:   (p1) U ((p2) V ((p3) && (!(p4))))\n",
      "Spot (default):     p1 U (p2 R (p3 & !p4))\n",
      "Spot+shell quotes:  'p1 U (p2 R (p3 & !p4))'\n",
      "LBT, right aligned: ~~~~~~~~~~~~~~~~~~~~~U p1 V p2 & p3 ! p4\n",
      "LBT, no M/W/R:      U p1 U & p3 ! p4 | & & p2 p3 ! p4 G & p3 ! p4\n"
     ]
    }
   ],
   "source": [
    "print(\"\"\"\\\n",
    "Spin:               {0:s}\n",
    "Spin+parentheses:   {0:sp}\n",
    "Spot (default):     {0}\n",
    "Spot+shell quotes:  {0:q}\n",
    "LBT, right aligned: {0:l:~>40}\n",
    "LBT, no M/W/R:      {0:[MWR]l}\"\"\".format(f))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The specifiers that can be used with `format` are documented as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function __format__ in module spot:\n",
      "\n",
      "__format__(self, spec)\n",
      "    Format the formula according to `spec`.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    spec : str, optional\n",
      "        a list of letters that specify how the formula\n",
      "        should be formatted.\n",
      "    \n",
      "    Supported specifiers\n",
      "    --------------------\n",
      "    \n",
      "    - 'f': use Spot's syntax (default)\n",
      "    - '8': use Spot's syntax in UTF-8 mode\n",
      "    - 's': use Spin's syntax\n",
      "    - 'l': use LBT's syntax\n",
      "    - 'w': use Wring's syntax\n",
      "    - 'x': use LaTeX output\n",
      "    - 'X': use self-contained LaTeX output\n",
      "    - 'j': use self-contained LaTeX output, adjusted for MathJax\n",
      "    \n",
      "    Add some of those letters for additional options:\n",
      "    \n",
      "    - 'p': use full parentheses\n",
      "    - 'c': escape the formula for CSV output (this will\n",
      "           enclose the formula in double quotes, and escape\n",
      "           any included double quotes)\n",
      "    - 'h': escape the formula for HTML output\n",
      "    - 'd': escape double quotes and backslash,\n",
      "           for use in C-strings (the outermost double\n",
      "           quotes are *not* added)\n",
      "    - 'q': quote and escape for shell output, using single\n",
      "           quotes or double quotes depending on the contents.\n",
      "    - '[...]': rewrite away all the operators specified in brackets,\n",
      "           using spot.unabbreviate().\n",
      "    \n",
      "    - ':spec': pass the remaining specification to the\n",
      "               formating function for strings.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(spot.formula.__format__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A `spot.formula` object has a number of built-in predicates whose value have been computed when the formula was constructed.  For instance you can check whether a formula is in negative normal form using `is_in_nenoform()`, and you can make sure it is an LTL formula (i.e. not a PSL formula) using `is_ltl_formula()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f.is_in_nenoform() and f.is_ltl_formula()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g.is_ltl_formula()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly, `is_syntactic_stutter_invariant()` tells wether the structure of the formula guarranties it to be stutter invariant.  For LTL formula, this means the `X` operator should not be used.  For PSL formula, this function capture all formulas built using the [siPSL grammar](http://www.daxc.de/eth/paper/09atva.pdf)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f.is_syntactic_stutter_invariant()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.formula('{a[*];b}<>->c').is_syntactic_stutter_invariant()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.formula('{a[+];b[*]}<>->d').is_syntactic_stutter_invariant()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`spot.relabel` renames the atomic propositions that occur in a formula, using either letters, or numbered propositions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\unicode{x201C}\\mathit{a > b}\\unicode{x201D} \\land \\unicode{x201C}\\mathit{proc[2]@init}\\unicode{x201D} \\land \\mathsf{G} \\mathsf{F} \\mathit{\\_foo\\_}$"
      ],
      "text/plain": [
       "\"a > b\" & \"proc[2]@init\" & GF_foo_"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gf = spot.formula('(GF_foo_) && \"a > b\" && \"proc[2]@init\"'); gf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$a \\land b \\land \\mathsf{G} \\mathsf{F} c$"
      ],
      "text/plain": [
       "a & b & GFc"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.relabel(gf, spot.Abc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$p_{0} \\land p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2}$"
      ],
      "text/plain": [
       "p0 & p1 & GFp2"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.relabel(gf, spot.Pnn)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The AST of any formula can be displayed with `show_ast()`.  Despite the name, this is not a tree but a DAG, because identical subtrees are merged.  Binary operators have their left and right operands denoted with `L` and `R`, while non-commutative n-ary operators have their operands numbered."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{a;b[*];c[+]}<>-> GFb\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": [
       "<svg height=\"260pt\" viewBox=\"0.00 0.00 269.00 260.00\" width=\"269pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g class=\"graph\" id=\"graph0\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
       "<title>G</title>\n",
       "<polygon fill=\"#ffffff\" points=\"-4,4 -4,-256 265,-256 265,4 -4,4\" stroke=\"transparent\"/>\n",
       "<!-- 0 -->\n",
       "<g class=\"node\" id=\"node1\">\n",
       "<title>0</title>\n",
       "<ellipse cx=\"98\" cy=\"-234\" fill=\"none\" rx=\"40.8928\" ry=\"18\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"98\" y=\"-230.3\">EConcat</text>\n",
       "</g>\n",
       "<!-- 1 -->\n",
       "<g class=\"node\" id=\"node2\">\n",
       "<title>1</title>\n",
       "<ellipse cx=\"155\" cy=\"-162\" fill=\"none\" rx=\"35.9954\" ry=\"18\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"155\" y=\"-158.3\">Concat</text>\n",
       "</g>\n",
       "<!-- 0&#45;&gt;1 -->\n",
       "<g class=\"edge\" id=\"edge6\">\n",
       "<title>0-&gt;1</title>\n",
       "<path d=\"M111.5082,-216.937C118.6068,-207.9703 127.4402,-196.8124 135.288,-186.8993\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"138.1259,-188.9535 141.5888,-178.9405 132.6375,-184.6085 138.1259,-188.9535\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"107.0082\" y=\"-205.737\">L</text>\n",
       "</g>\n",
       "<!-- 7 -->\n",
       "<g class=\"node\" id=\"node8\">\n",
       "<title>7</title>\n",
       "<ellipse cx=\"58\" cy=\"-162\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"58\" y=\"-158.3\">G</text>\n",
       "</g>\n",
       "<!-- 0&#45;&gt;7 -->\n",
       "<g class=\"edge\" id=\"edge9\">\n",
       "<title>0-&gt;7</title>\n",
       "<path d=\"M88.1124,-216.2022C83.3928,-207.7071 77.6537,-197.3767 72.4568,-188.0223\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"75.4145,-186.139 67.4985,-179.0972 69.2954,-189.5386 75.4145,-186.139\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"83.1124\" y=\"-205.0022\">R</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g class=\"node\" id=\"node3\">\n",
       "<title>2</title>\n",
       "<polygon fill=\"none\" points=\"261,-36 207,-36 207,0 261,0 261,-36\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"234\" y=\"-14.3\">a</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;2 -->\n",
       "<g class=\"edge\" id=\"edge1\">\n",
       "<title>1-&gt;2</title>\n",
       "<path d=\"M173.9318,-146.4771C184.9807,-136.5145 198.3956,-122.7193 207,-108 218.2008,-88.8391 225.1222,-64.624 229.1492,-46.139\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"232.5946,-46.7593 231.1469,-36.2639 225.7336,-45.3713 232.5946,-46.7593\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"170.4318\" y=\"-135.2771\">1</text>\n",
       "</g>\n",
       "<!-- 3 -->\n",
       "<g class=\"node\" id=\"node4\">\n",
       "<title>3</title>\n",
       "<ellipse cx=\"99\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"99\" y=\"-86.3\">Star</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;3 -->\n",
       "<g class=\"edge\" id=\"edge3\">\n",
       "<title>1-&gt;3</title>\n",
       "<path d=\"M141.7288,-144.937C134.6536,-135.8403 125.8244,-124.4886 118.0315,-114.4691\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"120.6927,-112.1897 111.7905,-106.4449 115.1672,-116.4873 120.6927,-112.1897\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"138.2288\" y=\"-133.737\">2</text>\n",
       "</g>\n",
       "<!-- 5 -->\n",
       "<g class=\"node\" id=\"node6\">\n",
       "<title>5</title>\n",
       "<ellipse cx=\"171\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"171\" y=\"-86.3\">Star</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;5 -->\n",
       "<g class=\"edge\" id=\"edge5\">\n",
       "<title>1-&gt;5</title>\n",
       "<path d=\"M159.0375,-143.8314C160.7941,-135.9266 162.8917,-126.4872 164.8363,-117.7365\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"168.2665,-118.4346 167.0192,-107.9134 161.4332,-116.916 168.2665,-118.4346\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"155.5375\" y=\"-132.6314\">3</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g class=\"node\" id=\"node5\">\n",
       "<title>4</title>\n",
       "<polygon fill=\"none\" points=\"90,-36 36,-36 36,0 90,0 90,-36\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"63\" y=\"-14.3\">b</text>\n",
       "</g>\n",
       "<!-- 3&#45;&gt;4 -->\n",
       "<g class=\"edge\" id=\"edge2\">\n",
       "<title>3-&gt;4</title>\n",
       "<path d=\"M90.2854,-72.5708C86.1772,-64.3544 81.1804,-54.3608 76.5911,-45.1821\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"79.613,-43.3996 72.0103,-36.0206 73.352,-46.5301 79.613,-43.3996\" stroke=\"#000000\"/>\n",
       "</g>\n",
       "<!-- 6 -->\n",
       "<g class=\"node\" id=\"node7\">\n",
       "<title>6</title>\n",
       "<polygon fill=\"none\" points=\"189,-36 135,-36 135,0 189,0 189,-36\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"162\" y=\"-14.3\">c</text>\n",
       "</g>\n",
       "<!-- 5&#45;&gt;6 -->\n",
       "<g class=\"edge\" id=\"edge4\">\n",
       "<title>5-&gt;6</title>\n",
       "<path d=\"M168.7289,-71.8314C167.7664,-64.131 166.6218,-54.9743 165.5521,-46.4166\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"169.0151,-45.9019 164.3017,-36.4133 162.0691,-46.7702 169.0151,-45.9019\" stroke=\"#000000\"/>\n",
       "</g>\n",
       "<!-- 8 -->\n",
       "<g class=\"node\" id=\"node9\">\n",
       "<title>8</title>\n",
       "<ellipse cx=\"27\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"#000000\"/>\n",
       "<text fill=\"#000000\" font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"27\" y=\"-86.3\">F</text>\n",
       "</g>\n",
       "<!-- 7&#45;&gt;8 -->\n",
       "<g class=\"edge\" id=\"edge8\">\n",
       "<title>7-&gt;8</title>\n",
       "<path d=\"M50.4958,-144.5708C46.905,-136.2309 42.5258,-126.0598 38.5254,-116.7686\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"41.7119,-115.319 34.5426,-107.5182 35.2825,-118.0872 41.7119,-115.319\" stroke=\"#000000\"/>\n",
       "</g>\n",
       "<!-- 8&#45;&gt;4 -->\n",
       "<g class=\"edge\" id=\"edge7\">\n",
       "<title>8-&gt;4</title>\n",
       "<path d=\"M35.7146,-72.5708C39.8228,-64.3544 44.8196,-54.3608 49.4089,-45.1821\" fill=\"none\" stroke=\"#000000\"/>\n",
       "<polygon fill=\"#000000\" points=\"52.648,-46.5301 53.9897,-36.0206 46.387,-43.3996 52.648,-46.5301\" stroke=\"#000000\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>"
      ],
      "text/plain": [
       "<IPython.core.display.SVG object>"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(g); g.show_ast()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any formula can also be classified in the temporal hierarchy of Manna & Pnueli"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg height=\"210\" version=\"1.1\" width=\"220\" xmlns=\"http://www.w3.org/2000/svg\">\n",
       "<polygon fill=\"cyan\" opacity=\".2\" points=\"20,0 200,120 200,210 20,210\"/>\n",
       "<polygon fill=\"cyan\" opacity=\".2\" points=\"20,120 155,210 20,210\"/>\n",
       "<polygon fill=\"magenta\" opacity=\".15\" points=\"200,0 20,120 20,210 200,210\"/>\n",
       "<polygon fill=\"magenta\" opacity=\".15\" points=\"200,120 65,210 200,210\"/>\n",
       "<g transform=\"translate(40,80)\">\n",
       "    <line stroke=\"red\" stroke-width=\"5\" x1=\"-10\" x2=\"10\" y1=\"-10\" y2=\"10\"/>\n",
       "    <line stroke=\"red\" stroke-width=\"5\" x1=\"-10\" x2=\"10\" y1=\"10\" y2=\"-10\"/>\n",
       "    </g>\n",
       "<g font-size=\"14\" text-anchor=\"middle\">\n",
       "<text x=\"110\" y=\"20\">Reactivity</text>\n",
       "<text x=\"60\" y=\"65\">Recurrence</text>\n",
       "<text x=\"160\" y=\"65\">Persistence</text>\n",
       "<text x=\"110\" y=\"125\">Obligation</text>\n",
       "<text x=\"60\" y=\"185\">Safety</text>\n",
       "<text x=\"160\" y=\"185\">Guarantee</text>\n",
       "</g>\n",
       "<g font-size=\"14\">\n",
       "<text fill=\"gray\" text-anchor=\"begin\" transform=\"rotate(-90,18,210)\" x=\"18\" y=\"210\">Monitor</text>\n",
       "<text fill=\"gray\" text-anchor=\"end\" transform=\"rotate(-90,18,0)\" x=\"18\" y=\"0\">Deterministic Büchi</text>\n",
       "<text fill=\"gray\" text-anchor=\"begin\" transform=\"rotate(-90,214,210)\" x=\"214\" y=\"210\">Terminal Büchi</text>\n",
       "<text fill=\"gray\" text-anchor=\"end\" transform=\"rotate(-90,214,0)\" x=\"214\" y=\"0\">Weak Büchi</text>\n",
       "</g>\n",
       "</svg>"
      ],
      "text/plain": [
       "<IPython.core.display.SVG object>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g.show_mp_hierarchy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'recurrence'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.mp_class(g, 'v')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\mathsf{F} (a \\land \\mathsf{X} (\\lnot a \\land b))$"
      ],
      "text/plain": [
       "F(a & X(!a & b))"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = spot.formula('F(a & X(!a & b))'); f"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Etessami's rule for removing X (valid only in stutter-invariant formulas)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$\\mathsf{F} (a \\land ((a \\land (a \\mathbin{\\mathsf{U}} (\\lnot a \\land b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} \\lnot a) \\lor (b \\mathbin{\\mathsf{U}} \\lnot a))) \\lor (\\lnot a \\land (\\lnot a \\mathbin{\\mathsf{U}} (a \\land \\lnot a \\land b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} a) \\lor (b \\mathbin{\\mathsf{U}} a))) \\lor (b \\land (b \\mathbin{\\mathsf{U}} (\\lnot a \\land b \\land \\lnot b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} \\lnot b) \\lor (a \\mathbin{\\mathsf{U}} \\lnot b))) \\lor (\\lnot b \\land (\\lnot b \\mathbin{\\mathsf{U}} (\\lnot a \\land b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} b) \\lor (a \\mathbin{\\mathsf{U}} b))) \\lor (\\lnot a \\land b \\land (\\mathsf{G} \\lnot a \\lor \\mathsf{G} a) \\land (\\mathsf{G} \\lnot b \\lor \\mathsf{G} b))))$"
      ],
      "text/plain": [
       "F(a & ((a & (a U (!a & b)) & ((!b U !a) | (b U !a))) | (!a & (!a U (a & !a & b)) & ((!b U a) | (b U a))) | (b & (b U (!a & b & !b)) & ((!a U !b) | (a U !b))) | (!b & (!b U (!a & b)) & ((!a U b) | (a U b))) | (!a & b & (G!a | Ga) & (G!b | Gb))))"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.remove_x(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Removing abbreviated operators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$(\\bot \\mathbin{\\mathsf{R}} \\lnot (a \\leftrightarrow b)) \\rightarrow (\\top \\mathbin{\\mathsf{U}} (a \\leftrightarrow b))$"
      ],
      "text/plain": [
       "(0 R !(a <-> b)) -> (1 U (a <-> b))"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = spot.formula(\"G(a xor b) -> F(a <-> b)\")\n",
    "spot.unabbreviate(f, \"GF^\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/latex": [
       "$(\\top \\mathbin{\\mathsf{U}} ((a \\land b) \\lor (\\lnot a \\land \\lnot b))) \\lor \\lnot (\\bot \\mathbin{\\mathsf{R}} ((\\lnot a \\land b) \\lor (a \\land \\lnot b)))$"
      ],
      "text/plain": [
       "(1 U ((a & b) | (!a & !b))) | !(0 R ((!a & b) | (a & !b)))"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "spot.unabbreviate(f, \"GF^ei\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nesting level of operators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "U 3\n",
      "F 2\n",
      "U 3\n",
      "F 2\n",
      "FU 4\n"
     ]
    }
   ],
   "source": [
    "f = spot.formula('F(b & X(a U b U ((a W Fb) | (c U d))))')\n",
    "print(\"U\", spot.nesting_depth(f, spot.op_U))\n",
    "print(\"F\", spot.nesting_depth(f, spot.op_F))\n",
    "# These following two are syntactic sugar for the above two\n",
    "print(\"U\", spot.nesting_depth(f, \"U\"))\n",
    "print(\"F\", spot.nesting_depth(f, \"F\"))\n",
    "# If you want to consider \"U\" and \"F\" are a similar type of\n",
    "# operator, you can count both with\n",
    "print(\"FU\", spot.nesting_depth(f, \"FU\"))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
