rename wrap/python/ to python/

* wrap/python/: Rename to...
* python/: ... this.
* wrap/: Delete.
* Makefile.am, README, configure.ac, debian/python3-spot.examples,
debian/rules, doc/org/.dir-locals.el.in, doc/org/init.el.in,
spot/sanity/ipynb.test: Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2015-12-25 11:55:31 +01:00
parent 74ec9c54c4
commit 34c3c1cedc
62 changed files with 24 additions and 48 deletions

13
python/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
.deps
.libs
Makefile
Makefile.in
*.la
spot_impl.py*
buddy.py*
*.lo
*.loT
*_wrap.*
*.pyc
*/spotimg
ajax/*.py

65
python/Makefile.am Normal file
View file

@ -0,0 +1,65 @@
## -*- coding: utf-8 -*-
## Copyright (C) 2010, 2011, 2013, 2014, 2015 Laboratoire de Recherche
## et Development de l'Epita (LRDE).
## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
## et Marie Curie.
##
## This file is part of Spot, a model checking library.
##
## Spot is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## Spot is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
## License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
SUBDIRS = . ajax tests
AM_CPPFLAGS = -I$(PYTHONINC) -I$(top_builddir) -I$(top_srcdir) \
$(BUDDY_CPPFLAGS) -DSWIG_TYPE_TABLE=spot
# Disable fastproxy, because IPython 2 bogusly ignores _repr_latex_
# when -fastproxy is used.
# https://github.com/ipython/ipython/issues/7003
# Once a fixed version of IPython hits Debian stable, we can remove
# this.
SWIGFLAGS = -c++ -python -py3 -O -nofastproxy
EXTRA_DIST = spot_impl.i buddy.i
python_PYTHON = $(srcdir)/spot_impl.py $(srcdir)/buddy.py spot.py
pyexec_LTLIBRARIES = _spot_impl.la _buddy.la
MAINTAINERCLEANFILES = \
$(srcdir)/spot_impl_wrap.cxx $(srcdir)/spot_impl.py \
$(srcdir)/buddy_wrap.cxx $(srcdir)/buddy.py
## spot
_spot_impl_la_SOURCES = $(srcdir)/spot_impl_wrap.cxx
_spot_impl_la_LDFLAGS = -avoid-version -module $(SYMBOLIC_LDFLAGS)
_spot_impl_la_LIBADD = $(top_builddir)/spot/libspot.la
$(srcdir)/spot_impl_wrap.cxx: $(srcdir)/spot_impl.i
$(SWIG) $(SWIGFLAGS) -I$(srcdir) -I$(top_srcdir) $(srcdir)/spot_impl.i
$(srcdir)/spot_impl.py: $(srcdir)/spot_impl.i
$(MAKE) $(AM_MAKEFLAGS) spot_impl_wrap.cxx
## buddy
_buddy_la_SOURCES = $(srcdir)/buddy_wrap.cxx
_buddy_la_LDFLAGS = -avoid-version -module $(BUDDY_LDFLAGS) $(SYMBOLIC_LDFLAGS)
$(srcdir)/buddy_wrap.cxx: $(srcdir)/buddy.i
$(SWIG) $(SWIGFLAGS) $(BUDDY_CPPFLAGS) $(srcdir)/buddy.i
$(srcdir)/buddy.py: $(srcdir)/buddy.i
$(MAKE) $(AM_MAKEFLAGS) buddy_wrap.cxx

41
python/ajax/Makefile.am Normal file
View file

@ -0,0 +1,41 @@
## -*- coding: utf-8 -*-
## Copyright (C) 2011, 2012, 2015 Laboratoire de Recherche
## et Développement de l'Epita (LRDE).
##
## This file is part of Spot, a model checking library.
##
## Spot is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## Spot is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
## License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
nodist_noinst_SCRIPTS = spotcgi.py
EXTRA_DIST = $(srcdir)/spotcgi.in README trans.html css/trans.css \
css/tipTip.css js/jquery.tipTip.minified.js js/jquery.ba-bbq.min.js \
js/jquery.ba-dotimeout.min.js logos/lip6sys64.png logos/lrde64.png \
logos/spot64s.png logos/mail.png css/loading.gif protocol.txt
CLEANFILES = $(nodist_noinst_SCRIPTS)
spotcgi.py: $(srcdir)/spotcgi.in Makefile
sed -e 's|[@]PYTHON[@]|@PYTHON@|g' \
-e 's|[@]pythondir[@]|@pythondir@|g' \
-e 's|[@]srcdir[@]|@srcdir@|g' \
-e 's|[@]top_builddir[@]|@top_builddir@|g' \
-e 's|[@]PACKAGE_VERSION[@]|@PACKAGE_VERSION@|g' \
-e 's|[@]DOT[@]|@DOT@|g' \
-e 's|[@]LTL3BA[@]|@LTL3BA@|g' \
<$(srcdir)/spotcgi.in >spotcgi.tmp
chmod +x spotcgi.tmp
mv -f spotcgi.tmp $@
clean-local:
rm -rf spotimg

90
python/ajax/README Normal file
View file

@ -0,0 +1,90 @@
ltl2tgba.html is a dynamic web page that translates user-supplied LTL
formulae to Transition-based Generalized Büchi Automata. The actual
translation work is performed by a CGI script in Python: spotcgi.py.
There are two ways to use the script: using a web server such as
Apache, or standalone.
In both cases you should ensure that the command `dot', from the
GraphViz package, is in the PATH. configure should have picked it up.
The "ltl3ba" tab will only be enabled if ltl3ba is available (as
checked by ./configure) and supports options -v/-T/-T3 (checked by the
CGI script). These option were introduced into ltl3ba version 1.1.0.
Standalone usage
================
Simply run spotcgi.py from this directory. This will create a directory
called spotimg/ in the current directory (this will hold the generated
pictures) and start an HTTP server on port 8000. Point your browser
to http://localhost:8000/trans.html and you should be OK.
After you have killed the server process (e.g. with Control-C),
you may want to erase the spotimg/ directory.
Installing on a real web server
===============================
1) Install Spot first (run `make install' from the top-level).
The CGI script uses the Python bindings and assume they
have been installed. Near the top of the script, you
should see a call to sys.path.insert(), with the expected
location of the Python bindings for spot. This path was
configured from ./configure's arguments and you should not
have to fiddle with it. I'm mentionning it just in case.
2) Copy spotcgi.py to some place were CGI execution is allowed.
Depending on your HTTP server's configuration, you may have
to rename the script as spotcgi.cgi or something else, so
that the server accepts to run it.
Apache users in trouble should look at the following options
before digging the Apache manual deeper. These can go
in a .htaccess file (if allowed).
# Treat *.py files as CGI scripts
AddHandler cgi-script .py
# Allow CGI execution in some directory.
Options +ExecCGI
3) In the directory where you have installed spotcgi.py,
create a subdirectory called spotimg/. This is where
the script will cache its images and other temporary
files. (If you want to change this name, see the imgdir
variable at the top of the script.)
This directory must be writable by the Unix user that
will run the script when the HTTP server processes the
request.
spotcgi.py purges old files at most once every hour.
4) Copy the directories css/, js/, and logos/ along with trans.html
to their destination. You may have to adjust a few paths at the
top of the html page.
Debugging
=========
When working on the script, remember that the contents of spotimg/ is
used as a cache and that a request will not be processed again if its
result is in the cache. So if you don't understand why the change you
have performed has no effect, make sure you are performing some fresh
query, or wipe the contents of the cache (i.e., erase all files inside
spotimg/ but not the spotimg/ directory itself).
The hash string displayed in the web browser is the query string sent
to the CGI script, so you can simulate the call from the command line
with a command like this:
% export QUERY_STRING="f=a+U+b&r=br&r=lf&r=si&r=eu&o=a&ff=o&mf=d&af=t&ra=t&rf=p&t=fm&fm=od&fm=sm&la=sp&ta=lc&as=ps&ec=Cou99&eo="
% export SCRIPT_NAME=spotcgi.py
% export SERVER_SOFTWARE=SimpleHTTP
% ./spotcgi.py

BIN
python/ajax/css/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

114
python/ajax/css/tipTip.css Normal file
View file

@ -0,0 +1,114 @@
/* TipTip CSS - Version 1.2 */
#tiptip_holder {
display: none;
position: absolute;
top: 0;
left: 0;
z-index: 99999;
}
#tiptip_holder.tip_top {
padding-bottom: 5px;
}
#tiptip_holder.tip_bottom {
padding-top: 5px;
}
#tiptip_holder.tip_right {
padding-left: 5px;
}
#tiptip_holder.tip_left {
padding-right: 5px;
}
#tiptip_content {
font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif;
font-size: 1em;
color: #fff;
text-shadow: 0 0 2px #000;
padding: 4px 8px;
border: 1px solid rgba(255,255,255,0.25);
background-color: rgb(25,25,25);
background-color: rgba(25,25,25,0.92);
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(transparent), to(#000));
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0 0 3px #555;
-webkit-box-shadow: 0 0 3px #555;
-moz-box-shadow: 0 0 3px #555;
}
#tiptip_arrow, #tiptip_arrow_inner {
position: absolute;
border-color: transparent;
border-style: solid;
border-width: 6px;
height: 0;
width: 0;
}
#tiptip_holder.tip_top #tiptip_arrow {
border-top-color: #fff;
border-top-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_bottom #tiptip_arrow {
border-bottom-color: #fff;
border-bottom-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_right #tiptip_arrow {
border-right-color: #fff;
border-right-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_left #tiptip_arrow {
border-left-color: #fff;
border-left-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_top #tiptip_arrow_inner {
margin-top: -7px;
margin-left: -6px;
border-top-color: rgb(25,25,25);
border-top-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
margin-top: -5px;
margin-left: -6px;
border-bottom-color: rgb(25,25,25);
border-bottom-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_right #tiptip_arrow_inner {
margin-top: -6px;
margin-left: -5px;
border-right-color: rgb(25,25,25);
border-right-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_left #tiptip_arrow_inner {
margin-top: -6px;
margin-left: -7px;
border-left-color: rgb(25,25,25);
border-left-color: rgba(25,25,25,0.92);
}
/* Webkit Hacks */
@media screen and (-webkit-min-device-pixel-ratio:0) {
#tiptip_content {
padding: 4px 8px 5px 8px;
background-color: rgba(45,45,45,0.88);
}
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
border-bottom-color: rgba(45,45,45,0.88);
}
#tiptip_holder.tip_top #tiptip_arrow_inner {
border-top-color: rgba(20,20,20,0.92);
}
}

139
python/ajax/css/trans.css Normal file
View file

@ -0,0 +1,139 @@
html {overflow-y:scroll;}
.ltl2tgba .ui-widget {
font-size: 1em;
}
input.formula {
width: 720px;
}
span#send {
width: 60px;
margin-left: 4px;
margin-right: 0px;
}
.shadow {
-moz-box-shadow: 2px 2px 2px #888888;
-webkit-box-shadow: 2px 1px 2px #888888;
box-shadow: 2px 2px 2px #888888;
}
div.ltl2tgba {
width: 800px;
position:relative;
left:0px;
top:0px;
margin-left: auto;
margin-right: auto;
z-index:10;
}
#spotlogo {
position:fixed;
left:10px;
top:10px;
z-index:1;
}
#lrdelogo {
position:fixed;
left:10px;
bottom:84px;
z-index:1;
}
#lip6logo {
position:fixed;
left:10px;
bottom:10px;
z-index:1;
}
#mailicon {
position:fixed;
left:10px;
top:84px;
z-index:1;
}
.ltldoc {
text-align: right;
}
table.ltltable
{
border-collapse:collapse;
font-size: 90%;
}
.ltldocrow {
font-weight: bold;
vertical-align:top;
}
.ltl2tgba div.ui-widget-content {
padding: 3px;
margin: 2px 0px;
background: #eeeeee;
}
.ltl2tgba h3 {
font-size:1em;
margin: 0;
padding: 0px 0.2em 0px;
border-bottom:1px solid #eee;
text-transform: capitalize;
}
.floatright {
float: right;
}
.colleft {
float: left;
width: 49%;
}
.ltl2tgba .head .ui-icon {
float: right;
margin: 1px 0px;
}
.ltl2tgba .formula, #tiptip_content .formula {
font-family: monospace;
font-weight: bold;
font-size: 1.1em;
}
.ltl2tgba .error {
color: red;
}
.ltl2tgba .parse-error {
font-family: monospace;
white-space: pre;
color: red;
font-size: 1.1em;
}
.ltl2tgba .ec-error {
color: red;
}
.ltl2tgba .loading {
display: block;
margin: 0 auto;
text-align: center;
}
.ltl2tgba .neverclaim, .ltl2tgba .accrun {
font-family: monospace;
white-space: pre;
font-size: 1.1em;
}
#ltl3ba-tab {
margin-left: 1em;
}
.ui-button-text-only .ui-button-text { padding: .1em .3em; }
.ui-tabs .ui-tabs-nav li a { float: left; padding: .1em .3em; text-decoration: none; }

18
python/ajax/js/jquery.ba-bbq.min.js vendored Normal file
View file

@ -0,0 +1,18 @@
/*
* jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
* http://benalman.com/projects/jquery-bbq-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($,r){var h,n=Array.prototype.slice,t=decodeURIComponent,a=$.param,j,c,m,y,b=$.bbq=$.bbq||{},s,x,k,e=$.event.special,d="hashchange",B="querystring",F="fragment",z="elemUrlAttr",l="href",w="src",p=/^.*\?|#.*$/g,u,H,g,i,C,E={};function G(I){return typeof I==="string"}function D(J){var I=n.call(arguments,1);return function(){return J.apply(this,I.concat(n.call(arguments)))}}function o(I){return I.replace(H,"$2")}function q(I){return I.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(K,P,I,L,J){var R,O,N,Q,M;if(L!==h){N=I.match(K?H:/^([^#?]*)\??([^#]*)(#?.*)/);M=N[3]||"";if(J===2&&G(L)){O=L.replace(K?u:p,"")}else{Q=m(N[2]);L=G(L)?m[K?F:B](L):L;O=J===2?L:J===1?$.extend({},L,Q):$.extend({},Q,L);O=j(O);if(K){O=O.replace(g,t)}}R=N[1]+(K?C:O||!N[1]?"?":"")+O+M}else{R=P(I!==h?I:location.href)}return R}a[B]=D(f,0,q);a[F]=c=D(f,1,o);a.sorted=j=function(J,K){var I=[],L={};$.each(a(J,K).split("&"),function(P,M){var O=M.replace(/(?:%5B|=).*$/,""),N=L[O];if(!N){N=L[O]=[];I.push(O)}N.push(M)});return $.map(I.sort(),function(M){return L[M]}).join("&")};c.noEscape=function(J){J=J||"";var I=$.map(J.split(""),encodeURIComponent);g=new RegExp(I.join("|"),"g")};c.noEscape(",/");c.ajaxCrawlable=function(I){if(I!==h){if(I){u=/^.*(?:#!|#)/;H=/^([^#]*)(?:#!|#)?(.*)$/;C="#!"}else{u=/^.*#/;H=/^([^#]*)#?(.*)$/;C="#"}i=!!I}return i};c.ajaxCrawlable(0);$.deparam=m=function(L,I){var K={},J={"true":!0,"false":!1,"null":null};$.each(L.replace(/\+/g," ").split("&"),function(O,T){var N=T.split("="),S=t(N[0]),M,R=K,P=0,U=S.split("]["),Q=U.length-1;if(/\[/.test(U[0])&&/\]$/.test(U[Q])){U[Q]=U[Q].replace(/\]$/,"");U=U.shift().split("[").concat(U);Q=U.length-1}else{Q=0}if(N.length===2){M=t(N[1]);if(I){M=M&&!isNaN(M)?+M:M==="undefined"?h:J[M]!==h?J[M]:M}if(Q){for(;P<=Q;P++){S=U[P]===""?R.length:U[P];R=R[S]=P<Q?R[S]||(U[P+1]&&isNaN(U[P+1])?{}:[]):M}}else{if($.isArray(K[S])){K[S].push(M)}else{if(K[S]!==h){K[S]=[K[S],M]}else{K[S]=M}}}}else{if(S){K[S]=I?h:""}}});return K};function A(K,I,J){if(I===h||typeof I==="boolean"){J=I;I=a[K?F:B]()}else{I=G(I)?I.replace(K?u:p,""):I}return m(I,J)}m[B]=D(A,0);m[F]=y=D(A,1);$[z]||($[z]=function(I){return $.extend(E,I)})({a:l,base:l,iframe:w,img:w,input:w,form:"action",link:l,script:w});k=$[z];function v(L,J,K,I){if(!G(K)&&typeof K!=="object"){I=K;K=J;J=h}return this.each(function(){var O=$(this),M=J||k()[(this.nodeName||"").toLowerCase()]||"",N=M&&O.attr(M)||"";O.attr(M,a[L](N,K,I))})}$.fn[B]=D(v,B);$.fn[F]=D(v,F);b.pushState=s=function(L,I){if(G(L)&&/^#/.test(L)&&I===h){I=2}var K=L!==h,J=c(location.href,K?L:{},K?I:2);location.href=J};b.getState=x=function(I,J){return I===h||typeof I==="boolean"?y(I):y(J)[I]};b.removeState=function(I){var J={};if(I!==h){J=x();$.each($.isArray(I)?I:arguments,function(L,K){delete J[K]})}s(J,2)};e[d]=$.extend(e[d],{add:function(I){var K;function J(M){var L=M[F]=c();M.getState=function(N,O){return N===h||typeof N==="boolean"?m(L,N):m(L,O)[N]};K.apply(this,arguments)}if($.isFunction(I)){K=I;return J}else{K=I.handler;I.handler=J}}})})(jQuery,this);
/*
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);

View file

@ -0,0 +1,9 @@
/*
* jQuery doTimeout: Like setTimeout, but better! - v1.0 - 3/3/2010
* http://benalman.com/projects/jquery-dotimeout-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($){var a={},c="doTimeout",d=Array.prototype.slice;$[c]=function(){return b.apply(window,[0].concat(d.call(arguments)))};$.fn[c]=function(){var f=d.call(arguments),e=b.apply(this,[c+f[0]].concat(f));return typeof f[0]==="number"||typeof f[1]==="number"?this:e};function b(l){var m=this,h,k={},g=l?$.fn:$,n=arguments,i=4,f=n[1],j=n[2],p=n[3];if(typeof f!=="string"){i--;f=l=0;j=n[1];p=n[2]}if(l){h=m.eq(0);h.data(l,k=h.data(l)||{})}else{if(f){k=a[f]||(a[f]={})}}k.id&&clearTimeout(k.id);delete k.id;function e(){if(l){h.removeData(l)}else{if(f){delete a[f]}}}function o(){k.id=setTimeout(function(){k.fn()},j)}if(p){k.fn=function(q){if(typeof p==="string"){p=g[p]}p.apply(m,d.call(n,i))===true&&!q?o():e()};o()}else{if(k.fn){j===undefined?e():k.fn(j===false);return true}else{e()}}}})(jQuery);

View file

@ -0,0 +1,21 @@
/*
* TipTip
* Copyright 2010 Drew Wilson
* www.drewwilson.com
* code.drewwilson.com/entry/tiptip-jquery-plugin
*
* Version 1.3 - Updated: Mar. 23, 2010
*
* This Plug-In will create a custom tooltip to replace the default
* browser tooltip. It is extremely lightweight and very smart in
* that it detects the edges of the browser window and will make sure
* the tooltip stays within the current window size. As a result the
* tooltip will adjust itself to be displayed above, below, to the left
* or to the right depending on what is necessary to stay within the
* browser window. It is completely customizable as well via CSS.
*
* This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
(function($){$.fn.tipTip=function(options){var defaults={activation:"hover",keepAlive:false,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:false,enter:function(){},exit:function(){}};var opts=$.extend(defaults,options);if($("#tiptip_holder").length<=0){var tiptip_holder=$('<div id="tiptip_holder" style="max-width:'+opts.maxWidth+';"></div>');var tiptip_content=$('<div id="tiptip_content"></div>');var tiptip_arrow=$('<div id="tiptip_arrow"></div>');$("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>')))}else{var tiptip_holder=$("#tiptip_holder");var tiptip_content=$("#tiptip_content");var tiptip_arrow=$("#tiptip_arrow")}return this.each(function(){var org_elem=$(this);if(opts.content){var org_title=opts.content}else{var org_title=org_elem.attr(opts.attribute)}if(org_title!=""){if(!opts.content){org_elem.removeAttr(opts.attribute)}var timeout=false;if(opts.activation=="hover"){org_elem.hover(function(){active_tiptip()},function(){if(!opts.keepAlive){deactive_tiptip()}});if(opts.keepAlive){tiptip_holder.hover(function(){},function(){deactive_tiptip()})}}else if(opts.activation=="focus"){org_elem.focus(function(){active_tiptip()}).blur(function(){deactive_tiptip()})}else if(opts.activation=="click"){org_elem.click(function(){active_tiptip();return false}).hover(function(){},function(){if(!opts.keepAlive){deactive_tiptip()}});if(opts.keepAlive){tiptip_holder.hover(function(){},function(){deactive_tiptip()})}}function active_tiptip(){opts.enter.call(this);tiptip_content.html(org_title);tiptip_holder.hide().removeAttr("class").css("margin","0");tiptip_arrow.removeAttr("style");var top=parseInt(org_elem.offset()['top']);var left=parseInt(org_elem.offset()['left']);var org_width=parseInt(org_elem.outerWidth());var org_height=parseInt(org_elem.outerHeight());var tip_w=tiptip_holder.outerWidth();var tip_h=tiptip_holder.outerHeight();var w_compare=Math.round((org_width-tip_w)/2);var h_compare=Math.round((org_height-tip_h)/2);var marg_left=Math.round(left+w_compare);var marg_top=Math.round(top+org_height+opts.edgeOffset);var t_class="";var arrow_top="";var arrow_left=Math.round(tip_w-12)/2;if(opts.defaultPosition=="bottom"){t_class="_bottom"}else if(opts.defaultPosition=="top"){t_class="_top"}else if(opts.defaultPosition=="left"){t_class="_left"}else if(opts.defaultPosition=="right"){t_class="_right"}var right_compare=(w_compare+left)<parseInt($(window).scrollLeft());var left_compare=(tip_w+left)>parseInt($(window).width());if((right_compare&&w_compare<0)||(t_class=="_right"&&!left_compare)||(t_class=="_left"&&left<(tip_w+opts.edgeOffset+5))){t_class="_right";arrow_top=Math.round(tip_h-13)/2;arrow_left=-12;marg_left=Math.round(left+org_width+opts.edgeOffset);marg_top=Math.round(top+h_compare)}else if((left_compare&&w_compare<0)||(t_class=="_left"&&!right_compare)){t_class="_left";arrow_top=Math.round(tip_h-13)/2;arrow_left=Math.round(tip_w);marg_left=Math.round(left-(tip_w+opts.edgeOffset+5));marg_top=Math.round(top+h_compare)}var top_compare=(top+org_height+opts.edgeOffset+tip_h+8)>parseInt($(window).height()+$(window).scrollTop());var bottom_compare=((top+org_height)-(opts.edgeOffset+tip_h+8))<0;if(top_compare||(t_class=="_bottom"&&top_compare)||(t_class=="_top"&&!bottom_compare)){if(t_class=="_top"||t_class=="_bottom"){t_class="_top"}else{t_class=t_class+"_top"}arrow_top=tip_h;marg_top=Math.round(top-(tip_h+5+opts.edgeOffset))}else if(bottom_compare|(t_class=="_top"&&bottom_compare)||(t_class=="_bottom"&&!top_compare)){if(t_class=="_top"||t_class=="_bottom"){t_class="_bottom"}else{t_class=t_class+"_bottom"}arrow_top=-12;marg_top=Math.round(top+org_height+opts.edgeOffset)}if(t_class=="_right_top"||t_class=="_left_top"){marg_top=marg_top+5}else if(t_class=="_right_bottom"||t_class=="_left_bottom"){marg_top=marg_top-5}if(t_class=="_left_top"||t_class=="_left_bottom"){marg_left=marg_left+5}tiptip_arrow.css({"margin-left":arrow_left+"px","margin-top":arrow_top+"px"});tiptip_holder.css({"margin-left":marg_left+"px","margin-top":marg_top+"px"}).attr("class","tip"+t_class);if(timeout){clearTimeout(timeout)}timeout=setTimeout(function(){tiptip_holder.stop(true,true).fadeIn(opts.fadeIn)},opts.delay)}function deactive_tiptip(){opts.exit.call(this);if(timeout){clearTimeout(timeout)}tiptip_holder.fadeOut(opts.fadeOut)}}})}})(jQuery);

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
python/ajax/logos/mail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

124
python/ajax/protocol.txt Normal file
View file

@ -0,0 +1,124 @@
This outlines the arguments passed by ltl2tgba.html to spot.py.
Specifying the formula to work with
f=... the formula
Formula simplifications (pick many)
r=br enable Basic Reductions
r=lf allow larger formulas
r=si enable Syntactic Implications
r=eu enable Eventuality and Universality
r=lc enable Language Containment
Choosing the desired output (pick one)
o=v output version (no other argument needed)
o=f output formula
o=m output monitor
o=a output automaton
o=r output run
o=t output testing automaton
o=v3 output LTL3BA's version (no other argument needed)
Type of formula output if o=f (pick one)
ff=o Spot syntax
ff=i Spin syntax
ff=l LBT syntax
ff=g graphviz output of the AST
ff=p property dump
Type of automaton if o=a (pick one)
af=t TGBA
af=s SBA
af=i Spin neverclaim
Type of monitor if o=m (pick one)
mf=d deterministic
mf=n nondeterministic
Type of automaton for run if o=r (pick one)
ra=t run on TGBA
ra=s run on SBA
Type of run output if o=r (pick one)
rf=p print run as text
rf=d draw run
Type of testing automaton if o=t (pick one)
tf=t TA
tf=g GTA
tf=a TGTA
Translator algorithm (pick one)
t=fm Couvreur/FM
t=la Couvreur/LaCIM
t=ta Tauriainen/TAA
t=l3 LTL3BA
t=cs Compositional Suspension
Couvreur/FM options if t=fm (pick many)
fm=od Optimize Determinism
fm=sm Symbolic Merge
fm=bp Branching Postponement
fm=fl Fair-Loop approximations
Couvreur/LA options if t=la
la=sp Symbolic Pruning
Tauriainen/TAA options if t=ta
ta=lc refined rules based on Language Containment
LTL3BA output options if t=l3 (pick one)
lo=T output a TGBA
lo=U output a BA
LTL3BA processing options if t=l3 (pick many)
l3=l LTL formula simplification
l3=P suspension in TGBA construction
l3=A suspension in alternating automaton construction
l3=C SCC simplifications
l3=M more deterministic output
l3=S direct simulation
l3=o on-the-fly simplifications
l3=p a-posteriori simplifications
Compositional Suspension options (pick many)
cs=w WDBA minimization
cs=s simulation
cs=e early start of suspended automatas
cs=c do not compose suspended formulae (for debugging)
cs=o compose obligation subformulae
Automaton simplifications (pick many)
as=ps Prune SCC
as=wd WDBA minimiztion
as=ds Direct Simulation reduction
as=rs Reverse Simulation reduction
as=is Iterated Simulation reduction (disables ds and rs)
Testing Automaton options (pick many)
to=l add a catch-all livelock state
to=s produce single-pass variant
to=m merge bisimilar states
Global options
g=8 Enable UTF-8 output.

850
python/ajax/spotcgi.in Executable file
View file

@ -0,0 +1,850 @@
#!@PYTHON@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche et
# Développement de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
script = ('SCRIPT_NAME' in os.environ)
if script:
# 3600s = 1h
sys.stdout.write("""Cache-Control: max-age=3600
Content-Type: text/html
""")
# Directory for temporary files (images and other auxiliary files).
imgdir = 'spotimg'
# Cache lookup for the QUERY_STRING
qs = os.getenv('QUERY_STRING')
if qs:
import hashlib
# We (optimistically) assume no collision from sha1(qs)
cachedir = imgdir + '/' + hashlib.sha1(qs.encode('utf-8')).hexdigest()
cachename = cachedir + '/html'
try:
# Is this a request we have already processed?
cache = open(cachename, "rb", 0)
if hasattr(sys.stdout, 'buffer'):
# Python 3+
sys.stdout.flush()
sys.stdout.buffer.write(cache.read())
else:
# Python 2.x
sys.stdout.write(cache.read())
# Touch the directory containing the files we used, so
# it that it survives the browser's cache.
os.utime(cachedir, None)
exit(0)
except IOError:
# We failed to open the file.
# Let's run the rest of the script to create it.
pass
elif script:
sys.stdout.write("<b>QUERY_STRING unset!</b>\n")
exit(0)
# Location of the dot command
dot = '@DOT@'
dot_bgcolor = '-Gbgcolor=#FFFFFF00'
svg_output = False # SVG output used to working well with Firefox
# only. It now seems to work with recent Chrome
# versions as well, but it is still a problem with
# Safari, and IE.
output_both = True # Create both PNG and SVG. If svg_output is False,
# the SVG will be given as a link under the PNG.
# Otherwise the PNG is used as alternate contents
# for the SVG object.
if not script:
# If this is not run as a cgi script, let's start an HTTP server.
try:
# Python 3+
from http.server import CGIHTTPRequestHandler, HTTPServer
except ImportError:
# Python 2.x
from CGIHTTPServer import CGIHTTPRequestHandler
from BaseHTTPServer import HTTPServer
class MyHandler(CGIHTTPRequestHandler):
def is_cgi(self):
if self.path.startswith('/cgi-bin/spotcgi.py'):
self.cgi_info = '', self.path[9:]
return True
return False
MyHandler.extensions_map[".hoa"] = 'text/x-hoa'
server_address=('', 8000)
if not os.access(imgdir, os.F_OK):
# 493 = 0755 but we would have to write 0755 or 0o755
# depending on the python version...
os.mkdir(imgdir, 493)
sys.stdout.write("Directory spotimg/ created.\n")
httpd = HTTPServer(server_address, MyHandler)
sys.stdout.write("Point your browser to http://localhost:8000/trans.html\n")
httpd.serve_forever()
import cgi
import signal
import time
import os.path
# We do not output in cachedir directely, in case two
# CGI scripts process the same request concurrently.
tmpdir = cachedir + '-' + str(os.getpid())
cachename = tmpdir + '/html'
sys.stdout.flush()
# Reopen stdout without buffering
sys.stdout = os.fdopen(sys.stdout.fileno(), "wb", 0)
# Redirect stderr to stdout at a low level (so that
# even errors from subprocesses get printed).
os.dup2(sys.stdout.fileno(), sys.stderr.fileno())
import cgitb
sys.excepthook = cgitb.Hook(file=sys.stderr)
# Create the temporary cache directory
os.mkdir(tmpdir, 493) # See comment above about 0o755 or 0755.
# Redirect stdout to the cache file, at a low level
# for similar reason.
fd = os.open(cachename, os.O_CREAT | os.O_WRONLY, 420) # 420 = 0644
os.dup2(fd, sys.stdout.fileno())
# We had to reopen stdout in binary mode to enable unbuffered output,
# (disallowed on text I/O by Python 3.x) so starting now, we are not
# allowed to send strings to sys.stdout. Always use the following
# method instead.
def unbufprint(s):
if sys.getdefaultencoding() != 'ascii' and type(s) != bytes:
sys.stdout.write(s.encode("utf-8"))
else:
sys.stdout.write(s)
def finish(kill = False):
# Output the result and exit.
os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
cache = open(cachename, "rb", 0)
sys.stdout.write(cache.read())
# Rename tmpdir to its permanent name for caching purpose.
# os.rename will fail if cachedir already exist. Since we tested
# that initially, it can only happen when two CGI script are
# processing the same request concurrently. In that case the
# other result is as good as ours, so we just ignore the error.
# (We don't bother removing the temporary directory -- it will be
# removed by the next cache prune and cannot be created again in
# the meantime.)
try:
os.rename(tmpdir, cachedir)
except OSError:
pass
if kill:
# Kill all children
os.kill(0, signal.SIGTERM)
# Should we prune the cache?
stamp = imgdir + '/cache.stamp'
now = time.time()
try:
# Prune at most once every hour
if now - os.path.getmtime(stamp) < 3600:
exit(0)
except OSError:
# It's OK if the file did not exist.
# We will create it.
pass
# Erase all directories that are older than 2 hours, and all
# files that have only one hardlinks. Files that have more than
# one hardlinks are referenced to by directories; so the hardlink
# count will decrease when the directory is purged.
os.system('find ' + imgdir + ' -mindepth 1 -maxdepth 1 -mmin +120 '
+ '\( -type d -o -links 1 \) -exec rm -rf {} +')
# Create or update the stamp so we know when to run the next prune.
open(stamp, "wb", 0)
exit(0)
# Assume Spot is installed
sys.path.insert(0, '@pythondir@')
if ('SERVER_SOFTWARE' in os.environ and
os.environ['SERVER_SOFTWARE'].startswith('SimpleHTTP')):
# We might be running from the build tree (but it's not sure).
# Add the build and source directories first in the search path.
# If we are not in the right place, python will find the installed
# libraries later.
sys.path.insert(0, '@srcdir@/../.libs')
sys.path.insert(0, '@srcdir@/..')
sys.path.insert(0, '../.libs')
sys.path.insert(0, '..')
# Darwin needs some help in figuring out where non-installed libtool
# libraries are (on this platform libtool encodes the expected final
# path of dependent libraries in each library).
m = '../.libs:@top_builddir@/spot/.libs:@top_builddir@/buddy/spot/.libs'
os.environ['DYLD_LIBRARY_PATH'] = m
try:
# execfile('ltl2tgba.opt') no longuer work with Python 3.
exec(compile(open("ltl2tgba.opt").read(), "ltl2tgba.opt", 'exec'))
except IOError:
pass
import spot
import buddy
spot.setup(size='8.2,8.2',fillcolor='#FDEDD3')
def alarm_handler(signum, frame):
unbufprint("""<p><font color="red">The script was aborted because
it has been running for too long.</font> Please try a shorter formula,
or different options.
If you want to benchmark big formulae it is
better to install Spot on your own computer.</p>\n""")
finish(kill = True)
def run_dot(basename, ext):
outname = basename + '.' + ext
# Do not call "dot" to generate a file that already exists.
if not os.access(outname, os.F_OK):
os.spawnlp(os.P_WAIT, dot, dot, dot_bgcolor, '-T' + ext,
'-o', outname, basename + '.txt')
# Create a unused hardlink that points to the output picture
# just to remember how many cache entries are sharing it.
os.link(outname, tmpdir + "/" + ext)
def render_dot(basename, hoaname = None):
unbufprint('<div class="dot">')
b = cgi.escape(basename)
if svg_output or output_both:
run_dot(basename, 'svg')
if not svg_output or output_both:
run_dot(basename, 'png')
pngstr = '<img src="' + b + '.png">'
if svg_output:
unbufprint('<object type="image/svg+xml" data="' + b + '.svg">')
if output_both:
unbufprint(pngstr)
else:
unbufprint('Your browser does not support SVG.')
unbufprint('</object>' + '<br>(<a href="' + b
+ '.txt">dot</a>)')
else:
unbufprint('<img src="' + b + '.png"><br>(<a href="' + b
+ '.txt">dot</a>)')
if output_both:
unbufprint(' (<a href="' + b + '.svg">svg</a>)')
if hoaname:
unbufprint(' (<a href="' + hoaname + '">hoa</a>)')
unbufprint('</div>\n')
def save_hoa(automaton):
hoasrc = spot.ostringstream()
spot.print_hoa(hoasrc, automaton, 't' if buchi_type == 't' else '')
hoasrc = hoasrc.str()
hoasrc += '\n'
if sys.getdefaultencoding() != 'ascii':
hoasrc = hoasrc.encode('utf-8')
autprefix = (imgdir + '/' + hashlib.sha1(hoasrc).hexdigest())
hoaname = autprefix + '.hoa'
if not os.access(hoaname, os.F_OK):
hoaout = open(hoaname, "wb", 0)
hoaout.write(hoasrc)
hoaout.close()
# Create a unused hardlink that points to the output HOA
# just to remember how many cache entries are sharing it.
os.link(hoaname, tmpdir + "/hoa")
return hoaname
def render_dot_maybe(dotsrc, dont_run_dot, hoaname = None):
# The dot output is named after the SHA1 of the dot source.
# This way we can cache two different requests that generate
# the same automaton (e.g., when changing a simplification
# option that has no influence).
if sys.getdefaultencoding() != 'ascii':
dotsrc = dotsrc.encode('utf-8')
# If the text rendering engine (usually Pango) used by dot does
# not draw overlines correctly, uncomment the following two
# lines. Pango 1.28.4 seems not to support combining overline
# while 1.30 does.
#import re
#dotsrc = re.sub(r'(.)(̅|̄)', r'¬\1', dotsrc);
autprefix = (imgdir + '/' + hashlib.sha1(dotsrc).hexdigest())
dotname = autprefix + '.txt'
if not os.access(dotname, os.F_OK):
dotout = open(dotname, "wb", 0)
dotout.write(dotsrc)
dotout.close()
# Create a unused hardlink that points to the output picture
# just to remember how many cache entries are sharing it.
os.link(dotname, tmpdir + "/txt")
if dont_run_dot:
unbufprint('<p>' + dont_run_dot + ''' to be rendered on-line.
However you may download the <a href="''' + cgi.escape(autprefix)
+ '.txt">source in dot format</a> and render it yourself.</p>\n')
else:
render_dot(autprefix, hoaname)
def render_automaton(automaton, dont_run_dot):
hoaname = None
dotsrc = spot.ostringstream()
if isinstance(automaton, spot.ta): # TA/GTA
spot.print_dot(dotsrc, automaton)
elif hasattr(automaton, 'get_ta'): # TGTA
spot.print_dot(dotsrc, automaton.get_ta())
else: # TGBA
if not dont_run_dot:
hoaname = save_hoa(automaton)
spot.print_dot(dotsrc, automaton, '.t' if buchi_type == 't' else '.')
render_dot_maybe(dotsrc.str(), dont_run_dot, hoaname)
def render_formula(f):
dotsrc = spot.ostringstream()
spot.print_dot_psl(dotsrc, f)
render_dot_maybe(dotsrc.str(), False)
def print_stats(automaton, detinfo = False, ta = False):
if ta: # TA/GTA
if hasattr(automaton, 'get_ta'): # TGTA
automaton = automaton.get_ta()
stats = spot.stats_reachable(automaton)
detinfo = False
else:
if (buchi_type == 't' and automaton.prop_inherently_weak() and
automaton.acc().is_buchi()):
unbufprint("Note: this is a weak automaton, using transition-based "
"or generalized acceptance does not bring any benefit."
"</br>")
stats = spot.sub_stats_reachable(automaton)
unbufprint("<p>%d state" % stats.states)
if stats.states > 1:
unbufprint("s")
if detinfo:
nondet = spot.count_nondet_states(automaton)
if nondet == 0:
unbufprint(" (deterministic)")
else:
unbufprint(" (%d nondeterministic)" % nondet)
if not hasattr(stats, 'transitions'):
unbufprint(", %d edge" % stats.edges)
if stats.edges > 1:
unbufprint("s")
else:
unbufprint(", %d edge%s (%d transition%s)"
% (stats.edges, 's' if stats.edges > 1 else '',
stats.transitions, 's' if stats.transitions > 1 else ''))
if hasattr(automaton, 'get_acceptance'):
acc = automaton.get_acceptance()
if (automaton.is_sba() and automaton.acc().is_buchi() and
buchi_type != 't'):
unbufprint(", acceptance condition: Büchi")
else:
unbufprint(", acceptance condition: " + str(acc))
if acc.is_tt():
unbufprint(" (all cycles are accepting)")
unbufprint("</p>\n")
# Decide whether we will render the automaton or not.
# (A webserver is not a computation center...)
if stats.states > 64:
return "Automaton has too many states"
if float(stats.edges)/stats.states > 10:
return "Automaton has too many edges per state"
return False
def format_formula(f, kind='div'):
if utf8:
s = f.to_str('utf8')
else:
s = f.to_str()
return '<%s class="formula spot-format">%s</%s>' % (kind, s, kind)
form = cgi.FieldStorage()
output_type = form.getfirst('o', 'v');
# Version requested.
if output_type == 'v':
unbufprint('Spot version %s\n' % spot.version())
finish()
# ltl3ba's version
if output_type == 'v3':
import subprocess
try:
l3proc = subprocess.Popen(['@LTL3BA@', '-v'], stdout=subprocess.PIPE)
(ver, err) = l3proc.communicate()
# -M[0|1] is new in 1.1.1, and we use it.
l3proc = subprocess.Popen(['@LTL3BA@', '-h'], stdout=subprocess.PIPE)
(out, err) = l3proc.communicate()
if out.find(b'-M[') < 0:
err = 1
else:
err = 0
except:
err = 1
if err != 0:
unbufprint('not available')
else:
unbufprint(ver.replace(b"\n", b"<br>"))
finish()
spot.unblock_signal(signal.SIGALRM)
spot.unblock_signal(signal.SIGTERM)
os.setpgrp()
child = os.fork()
if child != 0:
# In parent. We are just waiting for the termination of the
# child, or for the timeout alarm. On SIGALRM, we will kill the
# child.
#
# We cannot avoid forking, because Python will not deliver a
# signal when a C function is running. So if Spot takes too long
# to translate some formula, it would not get interrupted.
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(30)
os.waitpid(child, 0)
exit(0)
# Global options
utf8 = False
for g in form.getlist('g'):
if g == '8':
utf8 = True
spot.enable_utf8()
formula = form.getfirst('f', '')
env = spot.default_environment.instance()
pel = spot.empty_parse_error_list()
f = spot.parse_infix_psl(formula, pel, env)
if pel:
# Try the LBT parser in case someone is throwing LBT formulas at us.
pel2 = spot.empty_parse_error_list()
g = spot.parse_prefix_ltl(formula, pel2, env)
if pel2:
unbufprint('<div class="parse-error">')
err = spot.format_parse_errors(spot.get_cout(), formula, pel)
unbufprint('</div>')
else:
f = g
# Do not continue if we could not parse anything sensible.
if not f:
finish()
# Formula simplifications
simpopt = spot.tl_simplifier_options(False, False, False,
False, False, False, True)
dored = False
for r in form.getlist('r'):
dored = True
if r == 'br':
simpopt.reduce_basics = True
elif r == 'lf':
simpopt.reduce_size_strictly = False
elif r == 'si':
simpopt.synt_impl = True
elif r == 'eu':
simpopt.event_univ = True
elif r == 'lc':
simpopt.containment_checks = True
simpopt.containment_checks_stronger = True
if dored:
# Not keeping the ltl simplifier aive will also clear the as_bdd()
# cache.
f = spot.tl_simplifier(simpopt).simplify(f)
# Formula manipulation only.
if output_type == 'f':
formula_format = form.getfirst('ff', 'o')
# o = Spot, i = Spin, l = LBT, g = GraphViz, p = properties
if formula_format == 'o':
unbufprint(format_formula(f))
elif formula_format == 'i':
unbufprint('<div class="formula spin-format">'
+ spot.str_spin_ltl(f) + '</div>')
if f.is_psl_formula() and not f.is_ltl_formula():
s = ''
if simpopt.reduce_size_strictly:
s = '<br><b>Try enabling larger formula rewritings.</b>'
unbufprint('<div class="error">The above formula contains PSL operators that Spin will not understand.%s</div>' % s)
elif formula_format == 'l':
if not f.is_ltl_formula():
unbufprint('<div class="error">PSL formulas cannot be expressed in this format.</div>')
else:
unbufprint('<div class="formula lbt-format">' + spot.str_lbt_ltl(f) + '</div>')
elif formula_format == 'g':
render_formula(f)
elif formula_format == 'p':
if utf8:
s = spot.str_utf8_psl(f)
else:
s = str(f)
unbufprint('Properties for ' + format_formula(f, 'span') + '<ul>\n')
for p in spot.list_formula_props(f):
unbufprint('<li>%s</li>\n' % p)
# Attempt to refine the hierarchy class using WDBA minimization
if not f.is_syntactic_safety() or not f.is_syntactic_guarantee():
dict = spot.bdd_dict()
automaton = spot.ltl_to_tgba_fm(f, dict, False, True)
minimized = spot.minimize_obligation(automaton, f)
if minimized != automaton:
g = spot.is_terminal_automaton(minimized)
s = spot.is_safety_mwdba(minimized)
if s and not f.is_syntactic_safety():
unbufprint('<li>pathologic safety</li>')
if g and not f.is_syntactic_guarantee():
unbufprint('<li>pathologic guarantee</li>')
if not f.is_syntactic_obligation():
unbufprint('<li>obligation (although not syntactically)</li>')
else:
unbufprint('<li>not an obligation</li>')
minimized = 0
automaton = 0
if not f.is_syntactic_stutter_invariant():
if spot.is_stutter_invariant(f):
unbufprint('<li>stutter invariant</li>')
else:
unbufprint('<li>stutter sensitive</li>')
unbufprint('</ul>\n')
finish()
# Formula translation.
translator = form.getfirst('t', 'fm')
if f.is_psl_formula() and not f.is_ltl_formula() and translator != 'fm':
unbufprint('''<div class="error">The PSL formula %s
cannot be translated using this algorithm. Please use Couveur/FM.'''
% format_formula(f, 'span'))
finish()
dict = spot.make_bdd_dict()
if output_type == 't' and not spot.is_stutter_invariant(f):
unbufprint('<b>Warning:</b> Testing automata are only valid '
+ 'for stutter-insensitive formulas, but the input is not.</br>')
# Should the automaton be displayed as a SBA?
issba = False
if translator == 'fm':
exprop = False
symb_merge = False
branching_postponement = False
fair_loop_approx = False
for fm in form.getlist('fm'):
if fm == 'od':
exprop = True
elif fm == 'sm':
symb_merge = True
elif fm == 'bp':
branching_postponement = True
elif fm == 'fl':
fair_loop_approx = True
automaton = spot.ltl_to_tgba_fm(f, dict,
exprop, symb_merge,
branching_postponement, fair_loop_approx)
elif translator == 'ta':
refined_rules = False
if form.getfirst('ta', '') == 'lc':
refined_rules = True
automaton = spot.ensure_digraph(spot.ltl_to_taa(f, dict, refined_rules))
elif translator == 'l3':
l3out = '-H2'
# 1.0.1 had determinization and simulation turned off by default,
# we need -M0 and -S0 with 1.1.1 for the same effect
l3opt = { '-l', '-P', '-A', '-c', '-C', '-o', '-p', '-M0', '-S0' }
for lo in form.getfirst('lo', 'T'):
if lo == 'U':
l3out = '-H3'
issba = True
for l3 in form.getlist('l3'):
if l3 == 'l':
l3opt.remove('-l')
elif l3 == 'P':
l3opt.remove('-P')
elif l3 == 'A':
l3opt.remove('-A')
elif l3 == 'C':
l3opt.remove('-C')
l3opt.remove('-c')
elif l3 == 'M':
l3opt.remove('-M0')
l3opt.add('-M1')
elif l3 == 'S':
l3opt.remove('-S0')
l3opt.add('-S2') # was -S in 1.0.1
elif l3 == 'o':
l3opt.remove('-o')
elif l3 == 'p':
l3opt.remove('-p')
args = ["@LTL3BA@", l3out]
args.extend(l3opt)
# Relabel the formula in case it contains unsupported atomic
# propositions (e.g., starting with _ or double-quoted).
m = spot.relabeling_map()
g = spot.relabel(f, spot.Pnn, m)
args.extend(['-f', "'" + spot.str_spin_ltl(g) + "' |"])
try:
automaton = spot.automaton(" ".join(args))
except RuntimeError as e:
unbufprint('<div class="error">{}</div>'.format(e))
finish()
spot.relabel_here(automaton, m)
elif translator == 'cs':
donot_inject = False
cs_nowdba = True
cs_nosimul = True
cs_early_start = False
for cs in form.getlist('cs'):
if cs == 'c':
donot_inject = True
elif cs == 'w':
cs_nowdba = False
elif cs == 's':
cs_nosimul = False
elif cs == 'e':
cs_early_start = True
automaton = spot.compsusp(f, dict, cs_nowdba, cs_nosimul,
cs_early_start, donot_inject)
else:
unbufprint('''<div class="error">unsupported translator</div>''')
finish()
buchi_type = None
# Monitor output
if output_type == 'm':
issba = True
mf = form.getfirst('mf', 'd')
pp = spot.postprocessor()
pp.set_type(spot.postprocessor.Monitor)
if mf == 'd':
pp.set_pref(spot.postprocessor.Deterministic)
elif mf == 'n':
pp.set_pref(spot.postprocessor.Small)
automaton = pp.run(automaton, f)
unbufprint('<div class="automata-stats">')
dont_run_dot = print_stats(automaton)
unbufprint('</div>')
automaton.set_name(str(f))
render_automaton(automaton, dont_run_dot)
automaton = 0
finish()
# Automaton simplifications
prune_scc = False
wdba_minimize = False
direct_simul = False
reverse_simul = False
iterated_simul = False
for s in form.getlist('as'):
if s == 'ps':
prune_scc = True
elif s == 'wd':
wdba_minimize = True
elif s == 'ds':
direct_simul = True
elif s == 'rs':
reverse_simul = True
elif s == 'is':
iterated_simul = True
ta_type = None
if output_type == 'a':
buchi_type = form.getfirst('af', 't')
elif output_type == 'r':
buchi_type = form.getfirst('ra', 't')
elif output_type == 't':
ta_type = form.getfirst('tf', 't')
else:
unbufprint("Unkown output type 'o=%s'.\n" % output_type)
automaton = 0
finish()
degen = False
neverclaim = False
if buchi_type == 's' or ta_type == 't':
degen = True
elif buchi_type == 'i':
degen = True
neverclaim = True
if output_type == 't':
ta_type = form.getfirst('tf', 't')
if ta_type == 't':
degen = True
if prune_scc:
# Do not suppress all useless acceptance conditions if
# degeneralization or simulation is requested: keeping those that
# lead to accepting states usually helps.
automaton = spot.scc_filter(automaton, not (degen
or direct_simul
or reverse_simul
or iterated_simul))
if wdba_minimize:
minimized = spot.minimize_obligation(automaton, f)
if minimized != automaton:
automaton = minimized
minimized = 0
degen = False # No need to degeneralize anymore
direct_simul = False # No need to simulate anymore
reverse_simul = False
iterated_simul = False
if direct_simul and not iterated_simul:
automaton = spot.simulation(automaton)
if reverse_simul and not iterated_simul:
automaton = spot.cosimulation(automaton)
if iterated_simul:
automaton = spot.iterated_simulations(automaton)
if prune_scc and (direct_simul or reverse_simul):
# Make a second pass after the simulation, since these might leave
# extra acceptance conditions.
automaton = spot.scc_filter(automaton, not degen)
if degen or neverclaim:
degen = spot.degeneralize(automaton)
else:
degen = automaton
# Buchi Automaton Output
if output_type == 'a':
if buchi_type == 'i':
s = spot.ostringstream()
spot.print_never_claim(s, degen)
unbufprint('<div class="neverclaim">%s</div>' % cgi.escape(s.str()))
del s
else: # 't' or 's'
dont_run_dot = print_stats(degen, True)
automaton.set_name(str(f))
render_automaton(degen, dont_run_dot)
degen = 0
automaton = 0
finish()
# Testing automaton Output
if output_type == 't':
livelock = False
singlepass = False
bisimulation = False
for to in form.getlist('to'):
if to == 'l':
livelock = True
elif to == 's':
singlepass = True
elif to == 'm':
bisimulation = True
propset = spot.atomic_prop_collect_as_bdd(f, automaton)
if ta_type == 'a':
tautomaton = spot.tgba_to_tgta(degen, propset)
if bisimulation:
tautomaton = spot.minimize_tgta(tautomaton)
else:
tautomaton = spot.tgba_to_ta(degen, propset,
True, True, singlepass, livelock)
if bisimulation:
tautomaton = spot.minimize_ta(tautomaton)
dont_run_dot = print_stats(tautomaton, ta = True)
render_automaton(tautomaton, dont_run_dot)
tautomaton = 0
degen = 0
automaton = 0
finish()
# Buchi Run Output
if output_type == 'r':
print_acc_run = False
s = form.getfirst('rf', 'd')
draw_acc_run = False
if s == 'p':
print_acc_run = True
elif s == 'd':
draw_acc_run = True
err = ""
opt = (form.getfirst('ec', 'Cou99') + "(" +
form.getfirst('eo', '') + ")")
eci, err = spot.make_emptiness_check_instantiator(opt)
if not eci:
unbufprint('<div class="parse-error">Cannot parse "' + opt
+ '" near "' + err + '".</div>')
ec = 0
else:
ec_a = 0
n_acc = degen.acc().num_sets()
n_max = eci.max_acceptance_conditions()
n_min = eci.min_acceptance_conditions()
if (n_acc <= n_max):
if (n_acc >= n_min):
ec_a = degen
else:
unbufprint('<div class="ec-error">Cannot run ' + opt
+ ' on automata with less than ' + str(n_min)
+ ' acceptance condition.<br/>Please build '
+ 'a degeneralized B&uuml;chi automaton if you '
+ 'want to try this algorithm.</div>')
else:
unbufprint('<div class="ec-error">Cannot run ' + opt
+ ' on automata with more than ' + str(n_max)
+ ' acceptance condition.<br/>Please build '
+ 'a degeneralized B&uuml;chi automaton if you '
+ 'want to try this algorithm.</div>')
if ec_a:
ec = eci.instantiate(ec_a)
else:
ec = 0
if ec:
ec_res = ec.check()
if not ec_res:
unbufprint('<div class="ec">No accepting run found.</div>')
else:
ec_run = ec_res.accepting_run()
unbufprint('<div class="ec">An accepting run was found.<br/>')
if ec_run:
if print_acc_run:
unbufprint('<div class="accrun">%s</div>' %
cgi.escape(str(ec_run)))
if draw_acc_run:
render_automaton(ec_run.as_twa(), False)
del ec_run
del ec_res
unbufprint('</div>')
finish()

758
python/ajax/trans.html Normal file
View file

@ -0,0 +1,758 @@
<!doctype HTML public "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<title>Spot's online LTL-to-TGBA translator</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="keywords" content="Spot,LTL,automata,B&uuml;chi,translation,TGBA">
<meta name="description" content="Translate LTL or PSL formulas into B&uuml;chi automata online using the Spot model-checking library">
<link rev=Made href="mailto:spot@lrde.epita.fr" title="Spot's discussion list">
<link rel="stylesheet" href="css/tipTip.css">
<link rel="icon" href="http://spot.lrde.epita.fr/img/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="http://spot.lrde.epita.fr/img/favicon.ico" type="image/x-icon">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/ui-lightness/jquery-ui.css">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="css/trans.css">
<script type="text/javascript" src="js/jquery.tipTip.minified.js"></script>
<script type="text/javascript" src="js/jquery.ba-bbq.min.js"></script>
<script type="text/javascript" src="js/jquery.ba-dotimeout.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
$.spotvars = { autoupdate: false,
scrolldown: true,
internalchange: false};
$(".tabs").tabs();
$("#send").button();
$("#results").hide();
$("abbr").tipTip({maxWidth: "300px", delay: 1000,
edgeOffset: 3,
defaultPosition: "below"});
$(".rtip").tipTip({maxWidth: "300px", delay: 1000,
edgeOffset: 10,
defaultPosition: "right"});
$(".btip").tipTip({maxWidth: "300px", delay: 1000,
edgeOffset: 10,
defaultPosition: "bottom"});
$(".ftip").tipTip({maxWidth: "300px", delay: 1000,
edgeOffset: 4,
defaultPosition: "left",
content: "<b>Click<\/b> to fold/unfold.<br><b>Ctrl+Click<\/b> to remove (any option set will remain set)."
});
$(".restip").tipTip({maxWidth: "300px", delay: 1000,
edgeOffset: 4,
defaultPosition: "left",
content: "<b>Click<\/b> to fold/unfold.<br><b>Ctrl+Click<\/b> to remove."
});
$(".ltltip").tipTip({maxWidth: "300px", delay: 1000,
edgeOffset: 4,
defaultPosition: "left",
content: "<b>Click<\/b> to fold/unfold."
});
$("#brcheckbox").change(function() {
if (!$(this).is(':checked')) {
$("#lfcheckbox").removeAttr('checked');
}
})
$("#lfcheckbox").change(function() {
if ($(this).is(':checked')) {
$("#brcheckbox").attr('checked', true);
}
})
$("#ltl3ba-T").change(function() {
if ($(this).is(':checked')) {
$("#ltl3ba-S").removeAttr('checked');
}
})
$("#ltl3ba-S").change(function() {
if ($(this).is(':checked')) {
$("#ltl3ba-U").attr('checked', true);
}
})
$("#to-s").change(function() {
if ($(this).is(':checked')) {
$("#to-l").removeAttr('checked');
}
})
$("#to-l").change(function() {
if ($(this).is(':checked')) {
$("#to-s").removeAttr('checked');
}
})
$("#tf-t,#tf-g").change(function() {
if ($(this).is(':checked')) {
$("#to-l,#to-s").removeAttr('disabled');
}
})
$("#tf-a").change(function() {
if ($(this).is(':checked')) {
$("#to-l,#to-s").attr('disabled', true);
}
})
$("#as-ds,#as-rs").change(function() {
if ($(this).is(':checked')) {
$("#as-is").removeAttr('checked');
}
})
$("#as-is").change(function() {
if ($(this).is(':checked')) {
$("#as-ds,#as-rs").removeAttr('checked');
}
})
function hideOrShowPanels(output, duration) {
switch (output)
{
case 'f':
$('#translator-tabs,#autsimp-tabs,#run-tabs,#tester-tabs').hide(duration);
break;
case 'm':
$('#autsimp-tabs,#run-tabs,#tester-tabs').hide(duration);
$('#translator-tabs').not('.killed').show(duration);
break;
case 'a':
$('#translator-tabs,#autsimp-tabs').not('.killed').show(duration);
$('#run-tabs,#tester-tabs').hide(duration);
break;
case 't':
$('#translator-tabs,#autsimp-tabs,#tester-tabs').not('.killed').show(duration);
$('#run-tabs').hide(duration);
break;
case 'r':
$('#translator-tabs,#autsimp-tabs,#run-tabs').not('.killed').show(duration);
$('#tester-tabs').hide(duration);
break;
}
}
function updateFormFromHash(duration) {
var hashparam = jQuery.deparam.fragment();
if (jQuery.isEmptyObject(hashparam))
return;
if (!$.spotvars.internalchange)
$("input,select", "#trform").each(function() {
var name = this.name;
var value = [];
if (name && hashparam[name] != undefined) {
value = hashparam[name];
if (value.constructor != Array)
value = [value];
}
switch(this.type || this.tagName.toLowerCase()) {
case "radio":
case "checkbox":
this.checked = false;
for(var i = 0; i < value.length; i++) {
this.checked |= (value[i] == this.value);
}
break;
case "select":
for(var opt = 0; opt < this.options.length; opt++) {
var option = this.options[opt];
option.selected = false;
for (var i = 0; i < value.length; i++) {
option.selected |= (value[i] == option.value);
}
}
break;
default:
this.value=value.join(',');
}
});
$("#brcheckbox,#tf-a").change();
$.spotvars.autoupdate = true;
$.spotvars.internalchange = false;
var o = $('input[name="o"]').val();
hideOrShowPanels(o, duration);
$("#output-tabs").tabs('option', 'active',
$('#output-tabs a[href="#tabs-o' + o + '"]').parent().index() - 1);
var t = $('input[name="t"]').val();
$("#translator-tabs").tabs('option', 'active',
$('#translator-tabs a[href="#tabs-t' + t + '"]').parent().index() - 1);
updateResults();
}
$(window).bind('hashchange', function(e) { updateFormFromHash('fast') });
$.get("/cgi-bin/spotcgi.py", "o=v", function(data) {
$("#spottip").attr("title", "This page uses <b>" + data + "<\/b> to process LTL formulas and automata. Please download the <b>Spot<\/b> library and install it on your computer if you want to do the same from the command line, or from another program.")
.tipTip({maxWidth: "400px", delay: 1000,
edgeOffset: 10,
defaultPosition: "right"});
});
$.get("/cgi-bin/spotcgi.py", "o=v3", function(data) {
if (data != 'not available') {
$("#ltl3ba-link").attr("title", data)
.tipTip({maxWidth: "400px", delay: 1000,
edgeOffset: 10,
defaultPosition: "right"});
} else {
var index = $('#translator-tabs a[href="#tabs-tl3"]').parent().index();
$("#translator-tabs").tabs("option", "disabled", [index - 1]);
}
});
function fold(ui, callback) {
var icon = ui.children(".ui-icon");
icon.removeClass("ui-icon-circle-arrow-n")
.addClass("ui-icon-circle-arrow-s");
ui.siblings('[class!="dontcollapse"]').hide('fast', callback);
}
function unfold(ui, noshowsiblings) {
var icon = ui.children(".ui-icon");
icon.removeClass("ui-icon-circle-arrow-s")
.addClass("ui-icon-circle-arrow-n");
if (!noshowsiblings) {
ui.siblings('[class!="dontcollapse"]').show('fast');
}
}
function foldToggle(ui) {
var icon = ui.children(".ui-icon");
if (icon.hasClass("ui-icon-circle-arrow-n")) {
icon.removeClass("ui-icon-circle-arrow-n")
.addClass("ui-icon-circle-arrow-s");
ui.siblings('[class!="dontcollapse"]').hide('fast');
} else {
icon.removeClass("ui-icon-circle-arrow-s")
.addClass("ui-icon-circle-arrow-n");
ui.siblings('[class!="dontcollapse"]').show('fast');
}
}
function updateHash() {
var str = $("#trform").serialize();
// This will trigger updateResults.
window.location.hash = "#" + str;
$.spotvars.internalchange = true;
// updateResults();
}
function updateResults() {
// If the answer takes more that 200ms to arrive,
// display a busy indicator.
$.doTimeout('res-update', 200, function(){
$("#results-body").hide();
$("#results-loading").show();
$("#results").show();
unfold($("#results-head"), true);
})
// don't read window.location.hash, because
// it has been %-decoded by firefox, which
// cause problems when formulae include '&'.
var fragment = location.href.replace(/^[^#]*#?(.*)$/, '$1');
console.log("fragment: " + fragment);
$("#results-body")
.load("/cgi-bin/spotcgi.py",
fragment,
function(response, status, xhr) {
$.doTimeout('res-update');
if (status == "error") {
var msg = "Sorry but there was an error: ";
$("#results-body").html(msg + xhr.status + " "
+ xhr.statusText);
}
$("#results-loading").hide();
$("#results-body").show();
$("#results").show();
unfold($("#results-head"), true);
fold($("#ltl-head"), function() {
if ($.spotvars.scrolldown)
$('html,body').animate({scrollTop: $("#results-head").offset().top}, 'slow');
$.spotvars.scrolldown = false;
});
return true;
});
}
function autoUpdate() {
if ($.spotvars.autoupdate)
updateHash();
return $.spotvars.autoupdate;
}
$("#send").click(updateHash);
$("input,select").change(autoUpdate);
$('input[name="f"]').attr('spellcheck', false).focus()
.keydown(function(e){
if (e.keyCode == 13) {
$.spotvars.scrolldown = true;
updateHash();
}
});
$('.collapsible .head').click(function(e) {
var cl = e.target.classList;
if (!cl.contains('head')
&& !cl.contains('ui-icon-circle-arrow-n')
&& !cl.contains('ui-icon-circle-arrow-s')) {
return true;
}
if (e.ctrlKey) {
if ($(this).attr('id') != 'ltl-head')
$(this).parent().hide('fast').addClass("killed");
} else {
foldToggle($(this));
}
return false;
});
$("#output-tabs").on("tabsactivate", function(event, ui) {
var v = ui.newPanel[0].id[6]; // 'tabs-om' => 'm'.
$('input[name="o"]').val(v)
if (!autoUpdate())
hideOrShowPanels(v, 'fast')
return true;
});
$('#output-tabs').tabs('option', 'active', $('#tabs-oa').index());
$('#translator-tabs').on("tabsactivate", function(event, ui) {
$('input[name="t"]').val(ui.newPanel[0].id.substring(6));
autoUpdate();
return true;
});
// Update the form from the hash value
updateFormFromHash(0);
});
</script>
</head>
<body>
<div id="spotlogo">
<a href="http://spot.lrde.epita.fr/"><img border=0 src="logos/spot64s.png" alt="Spot Logo" class="rtip" id="spottip" title="This page uses the <b>Spot</b> library to process LTL formulas and automata. Please download <b>Spot</b> and install it on your computer if you want to do the same from the command line, or from another program."></a></div>
<div id="mailicon">
<a href="mailto:spot@lrde.epita.fr"><img border=0 src="logos/mail.png" alt="Spot Logo" class="rtip" title="A bug? A question? Please e-mail us at <b>spot@lrde.epita.fr</b>."></a></div>
<div id="lrdelogo">
<a href="https://www.lrde.epita.fr/"><img border=0 src="logos/lrde64.png" alt="LRDE Logo"></a></div>
<div id="lip6logo">
<a href="http://www.lip6.fr/"><img border=0 src="logos/lip6sys64.png" alt="LIP6 Logo"></a></div>
<div class="ltl2tgba">
<!-- The action below will not be used. -->
<FORM id="trform" action="#"><P>
<div class="ui-widget ui-widget-content ui-corner-all collapsible shadow">
<h3 id="ltl-head" class="ui-widget-header ui-corner-all head">LTL (or PSL) Formula to translate<span class="ui-icon ui-icon-circle-arrow-n ltltip">Fold</span></h3>
<div class="dontcollapse">
<INPUT class="formula" type="text" name="f" value=""><span id="send" class="btip" title="Submit the formula and all options. You may simply hit <b>enter</b> after typing the formula. After the first submission the form will auto-update itself anytime you change an option.">Send</span></div>
<div id="ltl-help">
<p>Use alphanumeric identifiers or double-quoted strings for atomic
propositions, and parentheses for grouping.<BR>Identifiers cannot
start with the letter of a prefix operator (<span class="formula">F</span>,
<span class="formula">G</span>, or <span class="formula">X</span>): for instance <span class="formula">GFa</span>
means <span class="formula">G(F(a))</span>. Use <span class="formula">"GFa"</span> if you really want
to refer to <span class="formula">GFa</span> as a proposition.<br>Conversely, infix
letter operators are not assumed to be operators if they are part of
an identifier: <span class="formula">aUb</span> is an atomic proposition, unlike
<span class="formula">a&nbsp;U&nbsp;b</span> and <span class="formula">(a)U(b)</span>.</p>
<table border="0" width="100%" rules="groups" frame="void" cellpadding="3" cellspacing="0" class="ltltable">
<colgroup>
<colgroup span=2>
<colgroup span=2>
<colgroup span=2>
<colgroup span=2>
<thead>
<tr>
<th></th>
<th colspan=2>Constants</th>
<th colspan=2>Unary operators</th>
<th colspan=4>Binary operators (infix)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="ltldocrow" rowspan=3>Boolean</td>
<td class="ltldoc">false:</td><td><span class="formula">0</span> <span class="formula">false</span></td>
<td class="ltldoc">not:</td><td><span class="formula">!</span> <span class="formula">~</span></td>
<td class="ltldoc">and:</td><td><span class="formula">&amp;</span> <span class="formula">&amp;&amp;</span>
<span class="formula">/\</span></td>
<td class="ltldoc">implies:</td><td><span class="formula">-&gt;</span>
<span class="formula">--&gt;</span>
<span class="formula">=&gt;</span></td>
</tr>
<tr>
<td class="ltldoc">true:</td><td><span class="formula">1</span> <span class="formula">true</span></td>
<td></td><td></td>
<td class="ltldoc">or:</td><td><span class="formula">|</span> <span class="formula">||</span>
<span class="formula">+</span> <span class="formula">\/</span></td>
<td class="ltldoc">equivalent:</td><td><span class="formula">&lt;-&gt;</span>
<span class="formula">&lt;--&gt;</span>
<span class="formula">&lt;=&gt;</span></td>
</tr>
<tr>
<td></td><td></td>
<td></td><td></td>
<td class="ltldoc">xor:</td><td><span class="formula">xor</span> <span class="formula">^</span></td>
<td></td><td></td>
</tr>
</tbody>
<tbody>
<tr>
<td class="ltldocrow" rowspan=3><ABBR title="Linear-time Temporal Logic">LTL</ABBR></td>
<td></td><td></td>
<td class="ltldoc">eventually:</td><td><span class="formula">F</span>
<span class="formula">&lt;&gt;</span></td>
<td class="ltldoc">(strong) until:</td><td><span class="formula">U</span></td>
<td class="ltldoc">weak until:</td><td><span class="formula">W</span></td>
</tr>
<tr>
<td></td><td></td>
<td class="ltldoc">always:</td><td><span class="formula">G</span>
<span class="formula">[]</span></td>
<td class="ltldoc">(weak) release:</td><td><span class="formula">R</span>
<span class="formula">V</span></td>
<td class="ltldoc">strong release:</td><td><span class="formula">M</span></td>
</tr>
<tr>
<td></td><td></td>
<td class="ltldoc">next:</td><td><span class="formula">X</span> <span class="formula">()</span></td>
<td></td><td></td>
<td></td><td></td>
</tr>
</tbody>
<tbody>
<tr>
<td class="ltldocrow" rowspan=4><ABBR title="Sequential Extended Regular
Expression">SERE</ABBR></td>
<td class="ltldoc">ε:</td><td><span class="formula">[*0]</span></td>
<td class="ltldoc">Kleene star:</td><td><span class="formula">[*] </span><span class="formula">[+]</span> <span class="formula">[*</span><i>i..j</i><span class="formula">]</span></td>
<td class="ltldoc">concatenation:</td><td><span class="formula">;</span></td>
<td class="ltldoc">fusion:</td><td><span class="formula">:</span></td>
</tr>
<tr>
<td></td><td></td>
<td class="ltldoc">goto:</td><td><span class="formula">[-></span><i>i..j</i><span class="formula">]</span></td>
<td class="ltldoc">intersection:</td><td><span class="formula">&amp;&amp;</span> <span class="formula">/\</span></td>
<td class="ltldoc"><ABBR title="Non-Length-Matching">NLM</ABBR> and:</td><td><span class="formula">&amp;</span></td>
</tr>
<tr>
<td></td><td></td>
<td class="ltldoc">nonconsec. rep.:</td><td><span class="formula">[=</span><i>i..j</i><span class="formula">]</span></td>
<td class="ltldoc">union:</td><td><span class="formula">|</span> <span class="formula">||</span> <span class="formula">+</span> <span class="formula">\/</span></td>
<td></td><td></td>
</tr>
<tr>
<td></td><td></td>
<td class="ltldoc"><abbr title="The operator <span class='formula'>[:+]</span> corresponds to the <span class='formula'>⊕</span> operator introduced by Dax et al. (<i>Specification Languages for Stutter-Invariant Regular Properties</i>, ATVA'09). The other two are generalizations to different bounds.">iterated fusion</abbr>:</td><td><span class="formula">[:*] </span><span class="formula">[:+]</span> <span class="formula">[:*</span><i>i..j</i><span class="formula">]</span></td>
<td></td><td></td>
<td></td><td></td>
</tr>
</tbody>
<tbody>
<tr>
<td class="ltldocrow" rowspan=2><ABBR title="Property Specification Language">PSL</ABBR></td>
<td></td><td></td>
<td class="ltldoc">weak closure:</td><td><span class="formula">{</span><i>s</i><span class="formula">}</span></td>
<td class="ltldoc">triggers:</td><td><span class="formula">{</span><i>s</i><span class="formula">}[]-></span><i>p</i><br><span class="formula">{</span><i>s</i><span class="formula">}|-></span><i>p</i><br><span class="formula">{</span><i>s</i><span class="formula">}(</span><i>p</i><span class="formula">)</span></td>
<td class="ltldoc"><ABBR title="Non-Overlapping">Non-Ov.</ABBR> trigger:</td><td><span class="formula">{</span><i>s</i><span class="formula">}[]=></span><i>p</i><br><span class="formula">{</span><i>s</i><span class="formula">}|=></span><i>p</i></td>
</tr>
<tr>
<td></td><td></td>
<td class="ltldoc">strong closure:</td><td><span class="formula">{</span><i>s</i><span class="formula">}!</span></td>
<td class="ltldoc">seq:</td><td><span class="formula">{</span><i>s</i><span class="formula">}&lt;&gt;-></span><i>p</i></td>
<td class="ltldoc"><ABBR title="Non-Overlapping">Non-Ov.</ABBR> seq:</td><td><span class="formula">{</span><i>s</i><span class="formula">}&lt;&gt;=></span><i>p</i></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="ui-widget ui-widget-content ui-corner-all collapsible shadow">
<h3 class="ui-widget-header ui-corner-all head">Formula Simplifications<span class="ui-icon ui-icon-circle-arrow-n ftip">Fold</span></h3>
<div>
<label class="rtip" title="Apply simple, unconditional rewriting rules to simplify formula. For instance <span class='formula'>F(a)|F(b)</span> is rewritten as <span class='formula'>F(a|b)</span>.">
<INPUT id="brcheckbox" type="checkbox" name="r" value="br" checked>
basic rewritings
</label>
<label class="rtip" title="Enable basic rewriting rules that may produce bigger formulas.">
<INPUT id="lfcheckbox" type="checkbox" name="r" value="lf" checked>
allow larger formulas
</label><br>
<label class="rtip" title="Use rewriting rules based on implications between subformulas, when these implications can be proved syntactically. For instance <span class='formula'>a U Fa</span> can be reduced to <span class='formula'>Fa</span> because the latter is obviously implied by <span class='formula'>a</span>.">
<INPUT type="checkbox" name="r" value="si" checked>
syntactic implication
</label><br>
<label class="rtip" title="Apply simplification rules when subformulas are <b>pure eventuality</b> or <b>purely universal</b>. For instance <span class='formula'>FGFa</span> can be rewritten to <span class='formula'>GFa</span> because the latter is a pure eventuality.">
<INPUT type="checkbox" name="r" value="eu" checked>
eventuality and universality
</label><br>
<label class="rtip" title="Try to reduce the formula by testing inclusion between automata built for various subformulas. This can be rather slow on large formulas.">
<INPUT type="checkbox" name="r" value="lc">
language containment
</label>
<label class="rtip floatright" title="Encode all formulas using UTF-8 characters.">
<INPUT type="checkbox" name="g" value="8">
UTF-8 output
</label>
</div>
</div>
<div id="output-tabs" class="tabs collapsible shadow">
<ul class="head">
<li>Desired Output:</li>
<li><a href="#tabs-of" class="btip" title="Simplify the formula, but do not convert it as an automaton.">Formula</a></li>
<li><a href="#tabs-om" class="btip" title="Create a monitor accepting all finite prefixes compatible with the formula.">Monitor</a></li>
<li><a href="#tabs-oa" class="btip" title="Translate the LTL formula into B&uuml;chi automaton.">B&uuml;chi Automaton</a></li>
<li><a href="#tabs-or" class="btip" title="Translate the LTL formula into B&uuml;chi automaton, and exhibit an accepting run.">B&uuml;chi Run</a></li>
<li><a href="#tabs-ot" class="btip" title="Translate the LTL formula into a Testing Automaton, or some variant.">Testing Automaton</a></li>
<li class="ui-icon ui-icon-circle-arrow-n ftip">Fold</li>
</ul>
<input type="hidden" name="o">
<div>
<div id="tabs-of">
Output the (simplified) formula as:<br>
<label class="rtip" title="Use letter operators (such as <span class='formula'>G</span> or <span class='formula'>F</span>) when possible, and unless UTF-8 output is activated.">
<INPUT type="radio" name="ff" value="o" checked>
text in Spot's syntax
</label><br>
<label class="rtip" title="This output can be given to Spin or any other tool using a similar syntax. Spot can also read it back. Operators such as such as <span class='formula'>M</span> and <span class='formula'>W</span>, which are not supported by Spin are rewritten away.">
<INPUT type="radio" name="ff" value="i">
text in Spin's syntax
</label><br>
<label class="rtip" title="This output can be given to LBT, LBTT, ltl2dstar, scheck, or any other tool using a similar syntax. Spot can also read it back. The original syntax only support atomic propositions named <span class='formula'>p0</span>, <span class='formula'>p1</span>, etc. As an extension, also supported by ltl2dstar, other atomic proposition are enclosed in double quotes. PSL formulas are not supported.">
<INPUT type="radio" name="ff" value="l">
text in LBT's syntax
</label><br>
<label class="rtip" title="A graphical representation of Spot's internal representation. Actually this is not a tree but an acyclic graph, because equal subformulas are shared.">
<INPUT type="radio" name="ff" value="g">
a syntactic tree
</label><br>
<label class="rtip" title="Various properties of the formula.">
<INPUT type="radio" name="ff" value="p">
property information
</label><br>
</div>
<div id="tabs-om">
Translate the (simplified) formula as:<br>
<label class="rtip" title="A deterministic monitor is a DFA that accepts all the prefixes of the executions that satisfy the formula.">
<INPUT type="radio" name="mf" value="d" checked>
a deterministic monitor
</label><br>
<label class="rtip" title="A nondeterministic monitor is an NFA that accepts all the prefixes of the executions that satisfy the formula.">
<INPUT type="radio" name="mf" value="n" checked>
a nondeterministic monitor
</label><br>
</div>
<div id="tabs-oa">
Translate the (simplified) formula as:<br>
<label class="rtip" title="A Transition-based Generalized B&uuml;chi Automaton (TGBA) is the main kind of automaton used by Spot. It is what all the translation algorithm below will output.">
<INPUT type="radio" name="af" value="t" checked>
a transition-based generalized B&uuml;chi automaton
</label><br>
<label class="rtip" title="Degeneralize the TGBA to obtain a B&uuml;chi automaton with a single set of accepting states.">
<INPUT type="radio" name="af" value="s">
a state-based degeneralized B&uuml;chi automaton
</label><br>
<label class="rtip" title="Degeneralize the TGBA to obtain a B&uuml;chi automaton with a single set of accepting states (as with previous option), then output the automaton as a neverclaim that can be fed to Spin.">
<INPUT type="radio" name="af" value="i">
a Spin neverclaim
</label><br>
</div>
<div id="tabs-or">
Translate the (simplified) formula as:<br>
<label class="rtip" title="A Transition-based Generalized B&uuml;chi Automaton (TGBA) is the main kind of automaton used by Spot. It is what all the translation algorithm below will output.">
<INPUT type="radio" name="ra" value="t" checked>
a transition-based generalized B&uuml;chi automaton
</label><br>
<label class="rtip" title="Degeneralize the TGBA to obtain a B&uuml;chi automaton with a single set of accepting states.">
<INPUT type="radio" name="ra" value="s">
a state-based degeneralized B&uuml;chi automaton
</label><br>
then<br>
<label class="rtip" title="Produce a textual description of run accepted by the automaton.">
<INPUT type="radio" name="rf" value="p">
print an accepting run
</label><br>
<label class="rtip" title="Use color to show an accepting run in the automaton.">
<INPUT type="radio" name="rf" value="d" checked>
draw an accepting run as a lasso-shaped automaton
</label><br>
</div>
<div id="tabs-ot">
Translate the (simplified) formula into a Büchi automaton, and then convert it into:<br>
<label class="rtip" title="Instead of reading valuations of all atomic propositions testing automata only watch the changes to these valuation. A transitions labeled by <span class='formula'>a</span> may be crossed only if these atomic proposition change in the system. Additionally, testing automata have two acceptance conditions: states can be Büchi accepting or livelock accepting (or both, or none).">
<INPUT id="tf-t" type="radio" name="tf" value="t">
a Testing Automaton (TA)
</label><br>
<label class="rtip" title="GTA are testing automata extended with multiple Büchi acceptance conditions.">
<INPUT id="tf-g" type="radio" name="tf" value="g">
a Generalized Testing Automaton (GTA)
</label><br>
<label class="rtip" title="TGTA are similar to TGBA except instead of reading valuations of all atomic propositions testing automata only watch the changes to these valuation. They have multiple Büchi acceptance conditions on transitions, but no livelock acceptance.">
<INPUT id="tf-a" type="radio" name="tf" value="a" checked>
a Transition-based Generalized Testing Automaton (TGTA)
</label><br>
</div>
</div>
</div>
<div id="translator-tabs" class="tabs collapsible shadow">
<ul class="head">
<li>Translator Algorithm:</li>
<li><a href="#tabs-tfm" class="btip" title="A tableau construction that uses BDDs to symbolically represent each state of the automaton. This produces better results than Tauriainen/TAA, and is the only algorithm that has been extended to support PSL operators.">Couvreur/FM</a></li>
<li><a href="#tabs-tta" class="btip" title="An implementation of Heikki Tauriainen's Ph.D. thesis algorithm to translate LTL formulas via very weak alternating automata with transition-based generalized acceptance conditions.">Tauriainen/TAA</a></li>
<li><a href="#tabs-tcs" class="btip" title="Compositional suspension.<br>A technique presented at Spin'13. Suspendable formulas are formulas such as <span class='formula'>GFa</span> or <span class='formula'>FGb</span> whose verification can always be postponed by a finite number of step. In this approach, we extract all suspendable subformulas, translate them separately from the main, skeleton automaton, only to merge them back in the accepting SCC. This translation uses Couvreur/FM for the intermediate parts.">Comp.Susp.</a></li>
<li id="ltl3ba-tab"><a href="#tabs-tl3" class="btip" title="An improved version of LTL2BA, overhauled by Tomáš Babiak during his Ph.D., and described at TACAS'12.<br>LTL3BA is not part of Spot. Options in this tab correspond to options offered by LTL3BA, and have some overlap with the options offered by Spot that are still applied before (LTL simplifications) and after (automata simplifications) LTL3BA is called.">LTL3BA</a></li>
<li class="ui-icon ui-icon-circle-arrow-n ftip">Fold</li>
</ul>
<input type="hidden" name="t" value="fm">
<div>
<div id="tabs-tfm">
<label class="rtip" title="Try to optimize the automaton for determinism when building it. Warning: this option can be expensive if the formula uses a lot of different atomic propositions because the algorithm has to consider all possible valuations.">
<INPUT type="checkbox" name="fm" value="od" checked>
optimize determinism
</label><br>
<label class="rtip" title="All states that share the same set of outgoing transitions will be merged. This optimization comes for free in the implementation, so there is no point in disabling it unless you want to study its effect.">
<INPUT type="checkbox" name="fm" value="sm" checked>
merge states with same symbolic successor representation
</label><br>
<label class="rtip" title="Attempt to delay non-deterministic branching. It sometimes helps to reduce the indeterminism (look at the effect on <span class='formula'>X(a) R b</span>), but it may also produce bigger automata.">
<INPUT type="checkbox" name="fm" value="bp">
branching postponement
</label><br>
<label class="rtip" title="Try to syntactically detect if a state can be part of a fair loop, and if so, do not use acceptance conditions for that state. This optimization seems to have more negative effects than positive effects...">
<INPUT type="checkbox" name="fm" value="fl">
fair-loop approximations
</label><br>
</div>
<div id="tabs-tta">
<label class="rtip" title="Enable a refined set of translation rules, based on language inclusion between subformulas. Because language inclusion between formula is tested using automata operations on translations for subformulas, this option can be slow.">
<INPUT type="checkbox" name="ta" value="lc" checked>
language containment
</label><br>
</div>
<div id="tabs-tl3">
Use <a href="http://sourceforge.net/projects/ltl3ba/" id="ltl3ba-link">LTL3BA</a> to build:
<label class="rtip" title="Stop LTL3BA once it has built a Transition-based Generalized Büchi Automaton. Spot will take it from here and optionally apply more optimizations.">
<INPUT id="ltl3ba-T" type="radio" name="lo" value="T" checked>
a TGBA
</label> or <label class="rtip" title="Run LTL3BA until it produces its final Büchi Automaton. Spot will consider this BA has a TGBA if further optimizations have been requested below.">
<INPUT id="ltl3ba-U" type="radio" name="lo" value="U">
a BA
</label><br>
<div class="colleft">
<label class="rtip" title="LTL simplifications performed in LTL3BA are independent of those Spot may have performed upstream.">
<INPUT type="checkbox" name="l3" value="l" checked>
LTL simplifications
</label><br>
<label class="rtip" title="See next tooltip for an explanation of suspension. LTL3BA supports suspension also in the construction of an intermediate alternating automaton, where it is only used for one step.">
<INPUT type="checkbox" name="l3" value="A" checked>
suspension in alternating automaton
</label><br>
<label class="rtip" title="Suspension is a technique to postpone the verification of some subformulae. An easy way to picture it is to look at the formula <span class='formula'>F(a)&amp;GF(b)</span>: the <span class='formula'>GF(b)</span> part does not need to be checked before some <span class='formula'>a</span> has been seen. On this example, suspension amounts to translating <span class='formula'>F(a&amp;GF(b))</span> but the technique is more general than such LTL rewritings.">
<INPUT type="checkbox" name="l3" value="P" checked>
suspension in TGBA
</label><br>
<label class="rtip" title="During the construction, each newly created transition or state is immediately compared to existing transitions or states and merged if possible.">
<INPUT type="checkbox" name="l3" value="o" checked>
on-the-fly simplifications
</label><br>
</div>
<label class="rtip" title="Perform the same simplifications as the on-the-fly simplification but on the final automaton, plus some SCC simplifications.">
<INPUT type="checkbox" name="l3" value="p" checked>
a-posteriori simplifications
</label><br>
<label class="rtip" title="Compute Strongly Connected Components to simplify the automaton.">
<INPUT type="checkbox" name="l3" value="C" checked>
SCC simplifications
</label><br>
<label class="rtip" title="Try to improve the automaton's determinism when building it. This may produce larger automata.">
<INPUT type="checkbox" name="l3" value="M" checked>
more deterministic output
</label><br>
<label class="rtip" title="Compute a direct (a.k.a. strong fair) simulation relation to reduce the size of the Büchi automaton.">
<INPUT id="ltl3ba-S" type="checkbox" name="l3" value="S">
direct simulation on BA
</label><br>
</div>
<div id="tabs-tcs">
<label class="rtip" title="Apply WDBA minimization on skeleton automaton when possible.">
<INPUT type="checkbox" name="cs" value="w">
WDBA minimization of intermediate automaton
</label><br>
<label class="rtip" title="Apply direct simulation on skeleton automaton. This is only done when the WDBA minimization could not work.">
<INPUT type="checkbox" name="cs" value="s" checked>
direct simulation on intermediate automaton
</label><br>
<label class="rtip" title="Start suspension on transitions that enter accepting SCCs instead of waiting to be in the SCC. (Not discussed in the Spin'13 paper.)">
<INPUT type="checkbox" name="cs" value="e">
early start of suspended automata
</label><br>
<label class="rtip" title="Output the skeleton automaton, with suspension labels showing where suspended formulae should be attached.
Unlike in our Spin'13 paper, we consider negated suspension labels and missing suspension labels
equivalently: the important data is the place of the positive suspension labels.">
<INPUT type="checkbox" name="cs" value="c">
do not compose suspended formulas (for debugging)
</label><br>
<!--
<label class="rtip" title="Consider obligation subformulas as atomic propositions initially, and compose their WDBA-minimized translation.">
<INPUT type="checkbox" name="cs" value="o">
compose WDBA-minimized obligation sub-formulas
</label><br> -->
</div>
</div>
</div>
<div id="autsimp-tabs" class="ui-widget ui-widget-content ui-corner-all collapsible shadow">
<h3 class="ui-widget-header ui-corner-all head">Automaton Simplifications<span class="ui-icon ui-icon-circle-arrow-n ftip">Fold</span></h3>
<div>
<label class="rtip" title="Compute the SCCs of the automaton. Eliminate all the useless SCCs (i.e. those that cannot be part of an accepting run). Also attempt to remove redundant acceptance conditions.">
<INPUT type="checkbox" name="as" value="ps" checked>
prune unaccepting SCCs
</label><br>
<label class="rtip" title="<b>Obligation properties</b> are properties that can be represented by a Weak Deterministic B&uuml;chi Automaton (WDBA). Any WDBA has a minimal form that can be constructed in a way that is similar to DFA minimization.<br>Using this option, any automaton (WDBA or not) will be tentatively determinized and minimized; the result will be used only if it is equivalent to the original automaton (i.e., if the property was indeed an obligation property).">
<INPUT type="checkbox" name="as" value="wd">
determinize and minimize obligation properties
</label><br>
<label class="rtip" title="Attempt to reduce the automaton by using <b>direct simulation</b> on the TGBA. Basically a state <b>A</b> can be merged into a state <b>B</b> if the <b>suffixes</b> reachable from <b>A</b> are included into those reachable from <b>B</b>. This algorithm may also improve determinism as a side effect.">
<INPUT id="as-ds" type="checkbox" name="as" value="ds">
direct simulation
</label>
<label class="rtip" title="Attempt to reduce the automaton by using <b>reverse simulation</b> on the TGBA. Basically a state <b>A</b> can be merged into a state <b>B</b> if the <b>prefixes</b> reachable from <b>A</b> are included into those reachable from <b>B</b> This can also improve codeterminism as a side effect.">
<INPUT id="as-rs" type="checkbox" name="as" value="rs">
reverse simulation
</label>
<label class="rtip" title="Apply <b>direct</b> and <b>reverse simulation</b> alternatively until the automaton is not reduced further.">
<INPUT id="as-is" type="checkbox" name="as" value="is">
iterated simulations
</label><br>
</div>
</div>
<div id="run-tabs" class="ui-widget ui-widget-content ui-corner-all collapsible shadow">
<h3 class="ui-widget-header ui-corner-all
head">Emptiness-check Algorithm<span class="ui-icon ui-icon-circle-arrow-n ftip">Fold</span></h3>
<div>
Search accepting run using algorithm:
<select name="ec">
<option value="Cou99" selected>Cou99</option>
<option value="CVWY90">CVWY90</option>
<option value="GV04">GV04</option>
<option value="SE05">SE05</option>
<option value="Tau03">Tau03</option>
<option value="Tau03_opt">Tau03_opt</option>
</select> with these
<a href="http://spot.lip6.fr/wiki/EmptinessCheckOptions">options</a>:
<INPUT type="text" maxlength="40" name="eo" value="">
</div>
</div>
<div id="tester-tabs" class="ui-widget ui-widget-content ui-corner-all collapsible shadow">
<h3 class="ui-widget-header ui-corner-all head">Testing Automaton Options<span class="ui-icon ui-icon-circle-arrow-n ftip">Fold</span></h3>
<div>
<label class="rtip" title="Divert all livelock accepting paths to a single livelock acceptance state.">
<INPUT id="to-l" type="checkbox" name="to" value="l">
use a catch-all livelock state
</label><br>
<label class="rtip" title="Ensure that all livelock accepting states are also Büchi-accepting, so that the testing automaton can be tested for emptiness in a single pass.">
<INPUT id="to-s" type="checkbox" name="to" value="s" checked>
produce a single-pass testing automaton
</label><br>
<label class="rtip" title="Merge bisimilar states in the final testing automaton.">
<INPUT type="checkbox" name="to" value="m" checked>
merge bisimilar states
</label><br>
</div>
</div>
</FORM>
<div id="results" class="ui-widget ui-widget-content ui-corner-all collapsible shadow">
<h3 id="results-head" class="ui-widget-header ui-corner-all head">Results<span class="ui-icon ui-icon-circle-arrow-n restip">Fold</span></h3>
<div id="results-loading" class="dontcollapse"><img src="css/loading.gif" class="loading" border=0 alt="loading..."></div>
<div id="results-body">
Loading...
</div>
</div>
</div>
</body>
</html>

365
python/buddy.i Normal file
View file

@ -0,0 +1,365 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2011, 2012, 2014 Laboratoire de Recherche et
// Développement de l'EPITA.
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// This is derived from Buddy's headers, distributed with the
// following license:
/*========================================================================
Copyright (C) 1996-2003 by Jorn Lind-Nielsen
All rights reserved
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, reproduce, prepare derivative
works, distribute, and display this software and its documentation
for any purpose, provided that (1) the above copyright notice and
the following two paragraphs appear in all copies of the source code
and (2) redistributions, including without limitation binaries,
reproduce these notices in the supporting documentation. Substantial
modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided
that the new terms are clearly indicated in all files where they apply.
IN NO EVENT SHALL JORN LIND-NIELSEN, OR DISTRIBUTORS OF THIS
SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE
ABOVE PARTIES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
JORN LIND-NIELSEN SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO
OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
========================================================================*/
%{
// Workaround for SWIG 2.0.2 using ptrdiff_t but not including cstddef.
// It matters with g++ 4.6.
#include <cstddef>
%}
%module buddy
%include "std_string.i"
%{
#include <sstream>
#include "bddx.h"
#include "fddx.h"
#include "bvecx.h"
%}
%typemap(in) (int* input_buf, int input_buf_size) {
if (!PySequence_Check($input))
{
PyErr_SetString(PyExc_ValueError, "Expected a sequence");
return 0;
}
$2 = PySequence_Length($input);
$1 = (int*) malloc($2 * sizeof(int));
for (int i = 0; i < $2; ++i)
{
PyObject* o = PySequence_GetItem($input, i);
if (PyInt_Check(o))
{
$1[i] = PyInt_AsLong(o);
}
else
{
PyErr_SetString(PyExc_ValueError,
"Sequence elements must be integers");
return 0;
}
}
}
%typemap(freearg) (int* input_buf, int input_buf_size) {
if ($1)
free($1);
}
%inline {
struct const_int_ptr
{
const_int_ptr(const int* ptr)
: ptr(ptr)
{
}
const int* ptr;
};
}
%extend const_int_ptr {
int
__getitem__(int i)
{
return self->ptr[i];
}
}
struct bdd
{
int id(void) const;
};
int bdd_init(int, int);
void bdd_done(void);
int bdd_setvarnum(int);
int bdd_extvarnum(int);
int bdd_isrunning(void);
int bdd_setmaxnodenum(int);
int bdd_setmaxincrease(int);
int bdd_setminfreenodes(int);
int bdd_getnodenum(void);
int bdd_getallocnum(void);
char* bdd_versionstr(void);
int bdd_versionnum(void);
void bdd_fprintstat(FILE *);
void bdd_printstat(void);
const char *bdd_errstring(int);
void bdd_clear_error(void);
bdd bdd_ithvar(int v);
bdd bdd_nithvar(int v);
int bdd_var(const bdd &r);
bdd bdd_low(const bdd &r);
bdd bdd_high(const bdd &r);
int bdd_scanset(const bdd &r, int *&v, int &n);
bdd bdd_makeset(int *v, int n);
int bdd_setbddpair(bddPair *p, int ov, const bdd &nv);
bdd bdd_replace(const bdd &r, bddPair *p);
bdd bdd_compose(const bdd &f, const bdd &g, int v);
bdd bdd_veccompose(const bdd &f, bddPair *p);
bdd bdd_restrict(const bdd &r, const bdd &var);
bdd bdd_constrain(const bdd &f, const bdd &c);
bdd bdd_simplify(const bdd &d, const bdd &b);
bdd bdd_ibuildcube(int v, int w, int *a);
bdd bdd_not(const bdd &r);
bdd bdd_apply(const bdd &l, const bdd &r, int op);
bdd bdd_and(const bdd &l, const bdd &r);
bdd bdd_or(const bdd &l, const bdd &r);
bdd bdd_xor(const bdd &l, const bdd &r);
bdd bdd_imp(const bdd &l, const bdd &r);
bdd bdd_biimp(const bdd &l, const bdd &r);
bdd bdd_setxor(const bdd &l, const bdd &r);
int bdd_implies(const bdd &l, const bdd &r);
bdd bdd_ite(const bdd &f, const bdd &g, const bdd &h);
bdd bdd_exist(const bdd &r, const bdd &var);
bdd bdd_existcomp(const bdd &r, const bdd &var);
bdd bdd_forall(const bdd &r, const bdd &var);
bdd bdd_forallcomp(const bdd &r, const bdd &var);
bdd bdd_unique(const bdd &r, const bdd &var);
bdd bdd_uniquecomp(const bdd &r, const bdd &var);
bdd bdd_appex(const bdd &l, const bdd &r, int op, const bdd &var);
bdd bdd_appexcomp(const bdd &l, const bdd &r, int op, const bdd &var);
bdd bdd_appall(const bdd &l, const bdd &r, int op, const bdd &var);
bdd bdd_appallcomp(const bdd &l, const bdd &r, int op, const bdd &var);
bdd bdd_appuni(const bdd &l, const bdd &r, int op, const bdd &var);
bdd bdd_appunicomp(const bdd &l, const bdd &r, int op, const bdd &var);
bdd bdd_support(const bdd &r);
bdd bdd_satone(const bdd &r);
bdd bdd_satoneset(const bdd &r, const bdd &var, const bdd &pol);
bdd bdd_fullsatone(const bdd &r);
void bdd_allsat(const bdd &r, bddallsathandler handler);
double bdd_satcount(const bdd &r);
double bdd_satcountset(const bdd &r, const bdd &varset);
double bdd_satcountln(const bdd &r);
double bdd_satcountlnset(const bdd &r, const bdd &varset);
int bdd_nodecount(const bdd &r);
int* bdd_varprofile(const bdd &r);
double bdd_pathcount(const bdd &r);
void bdd_fprinttable(FILE *file, const bdd &r);
void bdd_printtable(const bdd &r);
void bdd_fprintset(FILE *file, const bdd &r);
void bdd_printset(const bdd &r);
void bdd_printdot(const bdd &r);
void bdd_fprintdot(FILE* ofile, const bdd &r);
int bdd_fnprintdot(char* fname, const bdd &r);
int bdd_fnsave(char *fname, const bdd &r);
int bdd_save(FILE *ofile, const bdd &r);
int bdd_fnload(char *fname, bdd &r);
int bdd_load(FILE *ifile, bdd &r);
int bdd_addvarblock(const bdd &v, int f);
extern const bdd bddfalse;
extern const bdd bddtrue;
#define bddop_and 0
#define bddop_xor 1
#define bddop_or 2
#define bddop_nand 3
#define bddop_nor 4
#define bddop_imp 5
#define bddop_biimp 6
#define bddop_diff 7
#define bddop_less 8
#define bddop_invimp 9
#define BDD_REORDER_NONE 0
#define BDD_REORDER_WIN2 1
#define BDD_REORDER_WIN2ITE 2
#define BDD_REORDER_SIFT 3
#define BDD_REORDER_SIFTITE 4
#define BDD_REORDER_WIN3 5
#define BDD_REORDER_WIN3ITE 6
#define BDD_REORDER_RANDOM 7
%extend bdd {
// For Python 2.0
int __cmp__(bdd* b) { return b->id() - self->id(); }
// For Python 2.1+ and Python 3
bool __le__(bdd* b) { return self->id() <= b->id(); }
bool __lt__(bdd* b) { return self->id() < b->id(); }
bool __eq__(bdd* b) { return self->id() == b->id(); }
bool __ne__(bdd* b) { return self->id() != b->id(); }
bool __ge__(bdd* b) { return self->id() >= b->id(); }
bool __gt__(bdd* b) { return self->id() > b->id(); }
std::string
__str__(void)
{
std::ostringstream res;
res << "bdd(id=" << self->id() << ")";
return res.str();
}
bdd __and__(bdd& other) { return *self & other; }
bdd __xor__(bdd& other) { return *self ^ other; }
bdd __or__(bdd& other) { return *self | other; }
bdd __rshift__(bdd& other) { return *self >> other; }
bdd __lshift__(bdd& other) { return *self << other; }
bdd __sub__(bdd& other) { return *self - other; }
bdd __neg__(void) { return !*self; }
}
/************************************************************************/
int fdd_extdomain(int* input_buf, int input_buf_size);
int fdd_overlapdomain(int, int);
void fdd_clearall(void);
int fdd_domainnum(void);
int fdd_domainsize(int);
int fdd_varnum(int);
const_int_ptr fdd_vars(int);
bdd fdd_ithvar(int, int);
int fdd_scanvar(bdd, int);
int* fdd_scanallvar(bdd);
bdd fdd_ithset(int);
bdd fdd_domain(int);
bdd fdd_equals(int, int);
void fdd_printset(bdd);
void fdd_fprintset(FILE*, bdd);
int fdd_scanset(const bdd &, int *&, int &);
bdd fdd_makeset(int*, int);
int fdd_intaddvarblock(int, int, int);
int fdd_setpair(bddPair*, int, int);
int fdd_setpairs(bddPair*, int*, int*, int);
/************************************************************************/
bvec bvec_copy(bvec v);
bvec bvec_true(int bitnum);
bvec bvec_false(int bitnum);
bvec bvec_con(int bitnum, int val);
bvec bvec_var(int bitnum, int offset, int step);
bvec bvec_varfdd(int var);
bvec bvec_varvec(int bitnum, int *var);
bvec bvec_coerce(int bitnum, bvec v);
int bvec_isconst(bvec e);
int bvec_val(bvec e);
bvec bvec_map1(const bvec&, bdd (*fun)(const bdd &));
bvec bvec_map2(const bvec&, const bvec&, bdd (*fun)(const bdd &, const bdd &));
bvec bvec_map3(const bvec&, const bvec&, const bvec &,
bdd (*fun)(const bdd &, const bdd &, const bdd &));
bvec bvec_add(bvec left, bvec right);
bvec bvec_sub(bvec left, bvec right);
bvec bvec_mulfixed(bvec e, int c);
bvec bvec_mul(bvec left, bvec right);
int bvec_divfixed(const bvec &, int c, bvec &, bvec &);
int bvec_div(const bvec &, const bvec &, bvec &, bvec &);
bvec bvec_ite(bdd a, bvec b, bvec c);
bvec bvec_shlfixed(bvec e, int pos, bdd c);
bvec bvec_shl(bvec l, bvec r, bdd c);
bvec bvec_shrfixed(bvec e, int pos, bdd c);
bvec bvec_shr(bvec l, bvec r, bdd c);
bdd bvec_lth(bvec left, bvec right);
bdd bvec_lte(bvec left, bvec right);
bdd bvec_gth(bvec left, bvec right);
bdd bvec_gte(bvec left, bvec right);
bdd bvec_equ(bvec left, bvec right);
bdd bvec_neq(bvec left, bvec right);
class bvec
{
public:
bvec(void);
bvec(int bitnum);
bvec(int bitnum, int val);
bvec(const bvec &v);
~bvec(void);
void set(int i, const bdd &b);
int bitnum(void) const;
int empty(void) const;
bvec operator=(const bvec &src);
bvec operator&(const bvec &a) const;
bvec operator^(const bvec &a) const;
bvec operator|(const bvec &a) const;
bvec operator!(void) const;
bvec operator<<(int a) const;
bvec operator<<(const bvec &a) const;
bvec operator>>(int a) const;
bvec operator>>(const bvec &a) const;
bvec operator+(const bvec &a) const;
bvec operator-(const bvec &a) const;
bvec operator*(int a) const;
bvec operator*(const bvec a) const;
bdd operator<(const bvec &a) const;
bdd operator<=(const bvec &a) const;
bdd operator>(const bvec &a) const;
bdd operator>=(const bvec &a) const;
bdd operator==(const bvec &a) const;
bdd operator!=(const bvec &a) const;
};
%extend bvec {
std::string
__str__(void)
{
std::ostringstream res;
res << "bvec(bitnum=" << self->bitnum() << ")";
return res.str();
}
bdd
__getitem__(int i)
{
return (*self)[i];
}
}

874
python/spot.py Normal file
View file

@ -0,0 +1,874 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2014, 2015 Laboratoire de
# Recherche et Développement de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
if sys.hexversion < 0x03030000:
sys.exit("This module requires Python 3.3 or newer")
from spot_impl import *
import subprocess
import os
import signal
from functools import lru_cache
def _extend(*classes):
"""
Decorator that extends all the given classes with the contents
of the class currently being defined.
"""
def wrap(this):
for cls in classes:
for (name, val) in this.__dict__.items():
if name not in ('__dict__', '__weakref__') \
and not (name == '__doc__' and val is None):
setattr(cls, name, val)
return classes[0]
return wrap
_show_default = None
def setup(**kwargs):
"""Configure Spot for fancy display.
This is manly useful in Jupyter/IPython.
Note that this function needs to be called before any automaton is
displayed. Afterwards it will have no effect (you should restart
Python, or the Jupyter/IPython Kernel).
Parameters
----------
bullets : bool
whether to display acceptance conditions as UTF8 bullets
(default: True)
fillcolor : str
the color to use for states (default: '#ffffaa')
size : str
the width and height of the GraphViz output in inches
(default: '10.2,5')
font : str
the font to use in the GraphViz output (default: 'Lato')
show_default : str
default options for show()
"""
import os
s = ('size="{}" node[style=filled,fillcolor="{}"] '
'edge[arrowhead=vee, arrowsize=.7]')
os.environ['SPOT_DOTEXTRA'] = s.format(kwargs.get('size', '10.2,5'),
kwargs.get('fillcolor', '#ffffaa'))
bullets = 'B' if kwargs.get('bullets', True) else ''
d = 'rf({})'.format(kwargs.get('font', 'Lato')) + bullets
global _show_default
_show_default = kwargs.get('show_default', None)
os.environ['SPOT_DOTDEFAULT'] = d
# In version 3.0.2, Swig puts strongly typed enum in the main
# namespace without prefixing them. Latter versions fix this. So we
# can remove for following hack once 3.0.2 is no longer used in our
# build farm.
if 'op_ff' not in globals():
for i in ('ff', 'tt', 'eword', 'ap', 'Not', 'X', 'F', 'G',
'Closure', 'NegClosure', 'NegClosureMarked',
'Xor', 'Implies', 'Equiv', 'U', 'R', 'W', 'M',
'EConcat', 'EConcatMarked', 'UConcat', 'Or',
'OrRat', 'And', 'AndRat', 'AndNLM', 'Concat',
'Fusion', 'Star', 'FStar'):
globals()['op_' + i] = globals()[i]
del globals()[i]
# Global BDD dict so that we do not have to create one in user code.
_bdd_dict = make_bdd_dict()
# Add a small LRU cache so that when we display automata into a
# interactive widget, we avoid some repeated calls to dot for
# identical inputs.
@lru_cache(maxsize=64)
def _str_to_svg(str):
dotty = subprocess.Popen(['dot', '-Tsvg'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
dotty.stdin.write(str)
res = dotty.communicate()
return res[0].decode('utf-8')
def _ostream_to_svg(ostr):
return _str_to_svg(ostr.str().encode('utf-8'))
@_extend(twa, ta)
class twa:
def _repr_svg_(self, opt=None):
"""Output the automaton as SVG"""
ostr = ostringstream()
if opt is None:
global _show_default
opt = _show_default
print_dot(ostr, self, opt)
return _ostream_to_svg(ostr)
def show(self, opt=None):
"""Display the automaton as SVG, in the IPython/Jupyter notebook"""
if opt is None:
global _show_default
opt = _show_default
# Load the SVG function only if we need it. This way the
# bindings can still be used outside of IPython if IPython is
# not installed.
from IPython.display import SVG
return SVG(self._repr_svg_(opt))
@_extend(twa)
class twa:
def to_str(a, format='hoa', opt=None):
format = format.lower()
if format == 'hoa':
ostr = ostringstream()
print_hoa(ostr, a, opt)
return ostr.str()
if format == 'dot':
ostr = ostringstream()
print_dot(ostr, a, opt)
return ostr.str()
if format == 'spin':
ostr = ostringstream()
print_never_claim(ostr, a, opt)
return ostr.str()
if format == 'lbtt':
ostr = ostringstream()
print_lbtt(ostr, a, opt)
return ostr.str()
raise ValueError("unknown string format: " + format)
def save(a, filename, format='hoa', opt=None, append=False):
with open(filename, 'a' if append else 'w') as f:
s = a.to_str(format, opt)
f.write(s)
if s[-1] != '\n':
f.write('\n')
return a
@_extend(formula)
class formula:
def __init__(self, str):
"""Parse the given string to create a formula."""
self.this = parse_formula(str)
def show_ast(self):
"""Display the syntax tree of the formula."""
# Load the SVG function only if we need it. This way the bindings
# can still be used outside of IPython if IPython is not
# installed.
from IPython.display import SVG
ostr = ostringstream()
print_dot_psl(ostr, self)
return SVG(_ostream_to_svg(ostr))
def to_str(self, format='spot', parenth=False):
if format == 'spot' or format == 'f':
return str_psl(self, parenth)
elif format == 'spin' or format == 's':
return str_spin_ltl(self, parenth)
elif format == 'utf8' or format == '8':
return str_utf8_psl(self, parenth)
elif format == 'lbt' or format == 'l':
return str_lbt_ltl(self)
elif format == 'wring' or format == 'w':
return str_wring_ltl(self)
elif format == 'latex' or format == 'x':
return str_latex_psl(self, parenth)
elif format == 'sclatex' or format == 'X':
return str_sclatex_psl(self, parenth)
else:
raise ValueError("unknown string format: " + format)
def __format__(self, spec):
"""Format the formula according to `spec`.
Parameters
----------
spec : str, optional
a list of letters that specify how the formula
should be formatted.
Supported specifiers
--------------------
- 'f': use Spot's syntax (default)
- '8': use Spot's syntax in UTF-8 mode
- 's': use Spin's syntax
- 'l': use LBT's syntax
- 'w': use Wring's syntax
- 'x': use LaTeX output
- 'X': use self-contained LaTeX output
Add some of those letters for additional options:
- 'p': use full parentheses
- 'c': escape the formula for CSV output (this will
enclose the formula in double quotes, and escape
any included double quotes)
- 'h': escape the formula for HTML output
- 'd': escape double quotes and backslash,
for use in C-strings (the outermost double
quotes are *not* added)
- 'q': quote and escape for shell output, using single
quotes or double quotes depending on the contents.
- ':spec': pass the remaining specification to the
formating function for strings.
"""
syntax = 'f'
parent = False
escape = None
while spec:
c, spec = spec[0], spec[1:]
if c in ('f', 's', '8', 'l', 'w', 'x', 'X'):
syntax = c
elif c == 'p':
parent = True
elif c in ('c', 'd', 'h', 'q'):
escape = c
elif c == ':':
break
else:
raise ValueError("unknown format specification: " + c + spec)
s = self.to_str(syntax, parent)
if escape == 'c':
o = ostringstream()
escape_rfc4180(o, s)
s = '"' + o.str() + '"'
elif escape == 'd':
s = escape_str(s)
elif escape == 'h':
o = ostringstream()
escape_html(o, s)
s = o.str()
elif escape == 'q':
o = ostringstream()
quote_shell_string(o, s)
s = o.str()
return s.__format__(spec)
def traverse(self, func):
if func(self):
return
for f in self:
f.traverse(func)
def map(self, func):
k = self.kind()
if k in (op_ff, op_tt, op_eword, op_ap):
return self
if k in (op_Not, op_X, op_F, op_G, op_Closure,
op_NegClosure, op_NegClosureMarked):
return formula.unop(k, func(self[0]))
if k in (op_Xor, op_Implies, op_Equiv, op_U, op_R, op_W,
op_M, op_EConcat, op_EConcatMarked, op_UConcat):
return formula.binop(k, func(self[0]), func(self[1]))
if k in (op_Or, op_OrRat, op_And, op_AndRat, op_AndNLM,
op_Concat, op_Fusion):
return formula.multop(k, [func(x) for x in self])
if k in (op_Star, op_FStar):
return formula.bunop(k, func(self[0]), self.min(), self.max())
raise ValueError("unknown type of formula")
def automata(*sources, timeout=None, ignore_abort=True,
trust_hoa=True, debug=False):
"""Read automata from a list of sources.
Parameters
----------
*sources : list of str
These sources can be either commands (end with `|`),
textual represantations of automata (contain `\n`),
or filenames (else).
timeout : int, optional
Number of seconds to wait for the result of a command.
If None (the default), not limit is used.
ignore_abort : bool, optional
If True (the default), skip HOA atomata that ends with
`--ABORT--`, and return the next automaton in the stream.
If False, aborted automata are reported as syntax errors.
trust_hoa : bool, optional
If True (the default), supported HOA properies that
cannot be easily verified are trusted.
debug : bool, optional
Whether to run the parser in debug mode.
Notes
-----
The automata can be written in the `HOA format`_, as `never
claims`_, in `LBTT's format`_, or in `ltl2dstar's format`_.
.. _HOA format: http://adl.github.io/hoaf/
.. _never claims: http://spinroot.com/spin/Man/never.html
.. _LBTT's format:
http://www.tcs.hut.fi/Software/lbtt/doc/html/Format-for-automata.html
.. _ltl2dstar's format:
http://www.ltl2dstar.de/docs/ltl2dstar.html#output-format-dstar
If an argument ends with a `|`, then this argument is interpreted as
a shell command, and the output of that command (without the `|`)
is parsed.
If an argument contains a newline, then it is interpreted as
actual contents to be parsed.
Otherwise, the argument is assumed to be a filename.
The result of this function is a generator on all the automata
objects read from these sources. The typical usage is::
for aut in spot.automata(filename, command, ...):
# do something with aut
When the source is a command, and no `timeout` is specified,
parsing is done straight out of the pipe connecting the
command. So
for aut in spot.automata('randaut -H -n 10 2 |'):
process(aut)
will call `process(aut)` on each automaton as soon as it is output by
`randaut`, and without waiting for `randaut` to terminate.
However if `timeout` is passed, then `automata()` will wait for
the entire command to terminate before parsing its entire output.
If one command takes more than `timeout` seconds,
`subprocess.TimeoutExpired` is raised.
If any command terminates with a non-zero error,
`subprocess.CalledProcessError` is raised.
"""
o = automaton_parser_options()
o.debug = debug
o.ignore_abort = ignore_abort
o.trust_hoa = trust_hoa
o.raise_errors = True
for filename in sources:
try:
p = None
proc = None
if filename[-1] == '|':
# universal_newlines for str output instead of bytes
# when the pipe is read from Python (which happens
# when timeout is set).
proc = subprocess.Popen(filename[:-1], shell=True,
preexec_fn=os.setsid,
universal_newlines=True,
stdout=subprocess.PIPE)
if timeout is None:
p = automaton_stream_parser(proc.stdout.fileno(),
filename, o)
else:
try:
out, err = proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
# Using subprocess.check_output() with timeout
# would just kill the shell, not its children.
os.killpg(proc.pid, signal.SIGKILL)
raise
else:
ret = proc.wait()
if ret:
raise subprocess.CalledProcessError(ret,
filename[:-1])
finally:
proc = None
p = automaton_stream_parser(out, filename, o)
elif '\n' in filename:
p = automaton_stream_parser(filename, "<string>", o)
else:
p = automaton_stream_parser(filename, o)
a = True
while a:
# This returns None when we reach the end of the file.
a = p.parse(_bdd_dict).aut
if a:
yield a
finally:
# Make sure we destroy the parser (p) and the subprocess
# (prop) in the correct order...
del p
if proc is not None:
if not a:
# We reached the end of the stream. Wait for the
# process to finish, so that we get its exit code.
ret = proc.wait()
else:
# if a != None, we probably got there through an
# exception, and the subprocess might still be
# running. Check if an exit status is available
# just in case.
ret = proc.poll()
del proc
if ret:
raise subprocess.CalledProcessError(ret, filename[:-1])
# deleting o explicitely now prevents Python 3.5 from
# reporting the following error: "<built-in function
# delete_automaton_parser_options> returned a result with
# an error set". It's not clear to me if the bug is in Python
# or Swig. At least it's related to the use of generators.
del o
return
def automaton(filename, **kwargs):
"""Read a single automaton from a file.
See `spot.automata` for a list of supported formats."""
try:
return next(automata(filename, **kwargs))
except StopIteration:
raise RuntimeError("Failed to read automaton from {}".format(filename))
def _postproc_translate_options(obj, default_type, *args):
type_ = None
pref_ = None
optm_ = None
comp_ = 0
unam_ = 0
sbac_ = 0
def type_set(val):
nonlocal type_
if type_ is not None and type_ != val:
raise ValueError("type cannot be both {} and {}"
.format(type_, val))
elif val == 'generic':
type_ = postprocessor.Generic
elif val == 'tgba':
type_ = postprocessor.TGBA
elif val == 'ba':
type_ = postprocessor.BA
else:
assert(val == 'monitor')
type_ = postprocessor.Monitor
def pref_set(val):
nonlocal pref_
if pref_ is not None and pref_ != val:
raise ValueError("preference cannot be both {} and {}"
.format(pref_, val))
elif val == 'small':
pref_ = postprocessor.Small
elif val == 'deterministic':
pref_ = postprocessor.Deterministic
else:
assert(val == 'any')
pref_ = postprocessor.Any
def optm_set(val):
nonlocal optm_
if optm_ is not None and optm_ != val:
raise ValueError("optimization level cannot be both {} and {}"
.format(optm_, val))
if val == 'high':
optm_ = postprocessor.High
elif val.startswith('med'):
optm_ = postprocessor.Medium
else:
assert(val == 'low')
optm_ = postprocessor.Low
def misc_set(val):
nonlocal comp_, unam_, sbac_
if val == 'complete':
comp_ = postprocessor.Complete
elif val == 'sbacc' or val == 'state-based-acceptance':
sbac_ = postprocessor.SBAcc
else:
assert(val == 'unambiguous')
unam_ = postprocessor.Unambiguous
options = {
'tgba': type_set,
'ba': type_set,
'monitor': type_set,
'generic': type_set,
'small': pref_set,
'deterministic': pref_set,
'any': pref_set,
'high': optm_set,
'medium': optm_set,
'low': optm_set,
'complete': misc_set,
'unambiguous': misc_set,
'statebasedacceptance': misc_set,
'sbacc': misc_set,
}
for arg in args:
arg = arg.lower()
fn = options.get(arg)
if fn:
fn(arg)
else:
# arg is not an know option, but maybe it is a prefix of
# one of them
compat = []
f = None
for key, fn in options.items():
if key.startswith(arg):
compat.append(key)
f = fn
lc = len(compat)
if lc == 1:
f(compat[0])
elif lc < 1:
raise ValueError("unknown option '{}'".format(arg))
else:
raise ValueError("ambiguous option '{}' is prefix of {}"
.format(arg, str(compat)))
if type_ is None:
type_ = default_type
if pref_ is None:
pref_ = postprocessor.Small
if optm_ is None:
optm_ = postprocessor.High
obj.set_type(type_)
obj.set_pref(pref_ | comp_ | unam_ | sbac_)
obj.set_level(optm_)
def translate(formula, *args):
"""Translate a formula into an automaton.
Keep in mind that 'Deterministic' expresses just a preference that
may not be satisfied.
The optional arguments should be strings among the following:
- at most one in 'TGBA', 'BA', or 'Monitor'
(type of automaton to build)
- at most one in 'Small', 'Deterministic', 'Any'
(preferred characteristics of the produced automaton)
- at most one in 'Low', 'Medium', 'High'
(optimization level)
- any combination of 'Complete', 'Unambiguous', and
'StateBasedAcceptance' (or 'SBAcc' for short)
The default corresponds to 'tgba', 'small' and 'high'.
"""
a = translator(_bdd_dict)
_postproc_translate_options(a, postprocessor.TGBA, *args)
if type(formula) == str:
formula = parse_formula(formula)
return a.run(formula)
formula.translate = translate
def postprocess(automaton, *args, formula=None):
"""Post process an automaton.
This applies a number of simlification algorithms, depending on
the options supplied. Keep in mind that 'Deterministic' expresses
just a preference that may not be satisfied if the input is
not already 'Deterministic'.
The optional arguments should be strings among the following:
- at most one in 'Generic', 'TGBA', 'BA', or 'Monitor'
(type of automaton to build)
- at most one in 'Small', 'Deterministic', 'Any'
(preferred characteristics of the produced automaton)
- at most one in 'Low', 'Medium', 'High'
(optimization level)
- any combination of 'Complete' and 'StateBasedAcceptance'
(or 'SBAcc' for short)
The default corresponds to 'generic', 'small' and 'high'.
If a formula denoted by this automaton is known, pass it to as the
optional `formula` argument; it can help some algorithms by
providing an easy way to complement the automaton.
"""
p = postprocessor()
if type(automaton) == str:
automaton = globals()['automaton'](automaton)
_postproc_translate_options(p, postprocessor.Generic, *args)
return p.run(automaton, formula)
twa.postprocess = postprocess
# Wrap C++-functions into lambdas so that they get converted into
# instance methods (i.e., self passed as first argument
# automatically), because only used-defined functions are converted as
# instance methods.
def _add_twa_graph(meth):
setattr(twa_graph, meth, (lambda self, *args, **kwargs:
globals()[meth](self, *args, **kwargs)))
for meth in ('scc_filter', 'scc_filter_states',
'is_deterministic', 'is_unambiguous'):
_add_twa_graph(meth)
# Wrapper around a formula iterator to which we add some methods of formula
# (using _addfilter and _addmap), so that we can write things like
# formulas.simplify().is_X_free().
class formulaiterator:
def __init__(self, formulas):
self._formulas = formulas
def __iter__(self):
return self
def __next__(self):
return next(self._formulas)
# fun shoud be a predicate and should be a method of formula.
# _addfilter adds this predicate as a filter whith the same name in
# formulaiterator.
def _addfilter(fun):
def filtf(self, *args, **kwargs):
it = filter(lambda f: getattr(f, fun)(*args, **kwargs), self)
return formulaiterator(it)
def nfiltf(self, *args, **kwargs):
it = filter(lambda f: not getattr(f, fun)(*args, **kwargs), self)
return formulaiterator(it)
if fun[:3] == 'is_':
notfun = 'is_not_' + fun[3:]
elif fun[:4] == 'has_':
notfun = 'has_no_' + fun[4:]
else:
notfun = 'not_' + fun
setattr(formulaiterator, fun, filtf)
setattr(formulaiterator, notfun, nfiltf)
# fun should be a function taking a formula as its first parameter and
# returning a formula. _addmap adds this function as a method of
# formula and formulaiterator.
def _addmap(fun):
def mapf(self, *args, **kwargs):
return formulaiterator(map(lambda f: getattr(f, fun)(*args, **kwargs),
self))
setattr(formula, fun,
lambda self, *args, **kwargs:
globals()[fun](self, *args, **kwargs))
setattr(formulaiterator, fun, mapf)
def randltl(ap, n=-1, **kwargs):
"""Generate random formulas.
Returns a random formula iterator.
ap: the number of atomic propositions used to generate random formulas.
n: number of formulas to generate, or unbounded if n < 0.
**kwargs:
seed: seed for the random number generator (0).
output: can be 'ltl', 'psl', 'bool' or 'sere' ('ltl').
allow_dups: allow duplicate formulas (False).
tree_size: tree size of the formulas generated, before mandatory
simplifications (15)
boolean_priorities: set priorities for Boolean formulas.
ltl_priorities: set priorities for LTL formulas.
sere_priorities: set priorities for SERE formulas.
dump_priorities: show current priorities, do not generate any formula.
simplify:
0 No rewriting
1 basic rewritings and eventual/universal rules
2 additional syntactic implication rules
3 (default) better implications using containment
"""
opts = option_map()
output_map = {
"ltl": OUTPUTLTL,
"psl": OUTPUTPSL,
"bool": OUTPUTBOOL,
"sere": OUTPUTSERE
}
if isinstance(ap, list):
aprops = atomic_prop_set()
for elt in ap:
aprops.insert(formula.ap(elt))
ap = aprops
ltl_priorities = kwargs.get("ltl_priorities", None)
sere_priorities = kwargs.get("sere_priorities", None)
boolean_priorities = kwargs.get("boolean_priorities", None)
output = output_map[kwargs.get("output", "ltl")]
opts.set("output", output)
opts.set("seed", kwargs.get("seed", 0))
tree_size = kwargs.get("tree_size", 15)
if isinstance(tree_size, tuple):
tree_size_min, tree_size_max = tree_size
else:
tree_size_min = tree_size_max = tree_size
opts.set("tree_size_min", tree_size_min)
opts.set("tree_size_max", tree_size_max)
opts.set("unique", not kwargs.get("allow_dups", False))
opts.set("wf", kwargs.get("weak_fairness", False))
simpl_level = kwargs.get("simplify", 0)
if simpl_level > 3 or simpl_level < 0:
sys.stderr.write('invalid simplification level: ' + simpl_level)
return
opts.set("simplification_level", simpl_level)
rg = randltlgenerator(ap, opts, ltl_priorities, sere_priorities,
boolean_priorities)
dump_priorities = kwargs.get("dump_priorities", False)
if dump_priorities:
dumpstream = ostringstream()
if output == OUTPUTLTL:
print('Use argument ltl_priorities=STRING to set the following '
'LTL priorities:\n')
rg.dump_ltl_priorities(dumpstream)
print(dumpstream.str())
elif output == OUTPUTBOOL:
print('Use argument boolean_priorities=STRING to set the '
'following Boolean formula priorities:\n')
rg.dump_bool_priorities(dumpstream)
print(dumpstream.str())
elif output == OUTPUTPSL or output == OUTPUTSERE:
if output != OUTPUTSERE:
print('Use argument ltl_priorities=STRING to set the '
'following LTL priorities:\n')
rg.dump_psl_priorities(dumpstream)
print(dumpstream.str())
print('Use argument sere_priorities=STRING to set the '
'following SERE priorities:\n')
rg.dump_sere_priorities(dumpstream)
print(dumpstream.str())
print('Use argument boolean_priorities=STRING to set the '
'following Boolean formula priorities:\n')
rg.dump_sere_bool_priorities(dumpstream)
print(dumpstream.str())
else:
sys.stderr.write("internal error: unknown type of output")
return
class _randltliterator:
def __init__(self, rg, n):
self.rg = rg
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i == self.n:
raise StopIteration
f = self.rg.next()
if f is None:
sys.stderr.write("Warning: could not generate a new "
"unique formula after {} trials.\n"
.format(MAX_TRIALS))
raise StopIteration
self.i += 1
return f
return formulaiterator(_randltliterator(rg, n))
def simplify(f, **kwargs):
level = kwargs.get('level', None)
if level is not None:
return tl_simplifier(tl_simplifier_options(level)).simplify(f)
basics = kwargs.get('basics', True)
synt_impl = kwargs.get('synt_impl', True)
event_univ = kwargs.get('event_univ', True)
cont_checks = kwargs.get('containment_checks', False)
cont_checks_stronger = kwargs.get('containment_checks_stronger', False)
nenoform_stop_on_boolean = kwargs.get('nenoform_stop_on_boolean', False)
reduce_size_strictly = kwargs.get('reduce_size_strictly', False)
boolean_to_isop = kwargs.get('boolean_to_isop', False)
favor_event_univ = kwargs.get('favor_event_univ', False)
simp_opts = tl_simplifier_options(basics,
synt_impl,
event_univ,
cont_checks,
cont_checks_stronger,
nenoform_stop_on_boolean,
reduce_size_strictly,
boolean_to_isop,
favor_event_univ)
return tl_simplifier(simp_opts).simplify(f)
for fun in dir(formula):
if (callable(getattr(formula, fun)) and (fun[:3] == 'is_' or
fun[:4] == 'has_')):
_addfilter(fun)
for fun in ['remove_x', 'relabel', 'relabel_bse',
'simplify', 'unabbreviate']:
_addmap(fun)
# Better interface to the corresponding C++ function.
def sat_minimize(aut, acc=None, colored=False,
state_based=False, states=0,
max_states=0, dichotomy=False):
args=''
if acc is not None:
if type(acc) is not str:
raise ValueError("argument 'acc' should be a string")
args += ',acc="' + acc + '"'
if colored:
args += ',colored'
if states:
if type(states) is not int or states < 0:
raise ValueError("argument 'states' should be a positive integer")
args += ',states=' + str(states)
if max_states:
if type(max_states) is not int or max_states < 0:
raise ValueError("argument 'states' should be a positive integer")
args += ',max-states=' + str(max_states)
if dichotomy:
args += ',dichotomy';
from spot_impl import sat_minimize as sm
return sm(aut, args, state_based)

694
python/spot_impl.i Normal file
View file

@ -0,0 +1,694 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique
// de Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
%{
// Workaround for SWIG 2.0.2 using ptrdiff_t but not including cstddef.
// It matters with g++ 4.6.
#include <cstddef>
%}
%module(director="1") spot_impl
%include "std_shared_ptr.i"
%include "std_vector.i"
%include "std_string.i"
%include "std_list.i"
%include "std_set.i"
%include "std_map.i"
%include "std_pair.i"
%include "stdint.i"
%include "exception.i"
%include "typemaps.i"
// git grep 'typedef.*std::shared_ptr' | grep -v const |
// sed 's/.*<\(.*\)>.*/%shared_ptr(spot::\1)/g'
%shared_ptr(spot::dstar_aut)
%shared_ptr(spot::parsed_aut)
%shared_ptr(spot::fair_kripke)
%shared_ptr(spot::kripke)
%shared_ptr(spot::kripke_graph)
%shared_ptr(spot::kripke)
%shared_ptr(spot::ta)
%shared_ptr(spot::ta_explicit)
%shared_ptr(spot::ta_product)
%shared_ptr(spot::tgta)
%shared_ptr(spot::tgta_explicit)
%shared_ptr(spot::bdd_dict)
%shared_ptr(spot::twa)
%shared_ptr(spot::twa_graph)
%shared_ptr(spot::twa_product)
%shared_ptr(spot::twa_product_init)
%shared_ptr(spot::taa_tgba)
%shared_ptr(spot::taa_tgba_string)
%shared_ptr(spot::taa_tgba_formula)
%shared_ptr(spot::twa_safra_complement)
%shared_ptr(spot::twa_run)
%shared_ptr(spot::emptiness_check_result)
%shared_ptr(spot::emptiness_check)
%shared_ptr(spot::emptiness_check_instantiator)
%shared_ptr(spot::tgbasl)
%import "buddy.i"
%{
#include <iostream>
#include <fstream>
#include <sstream>
#include <signal.h>
#include <spot/misc/common.hh>
#include <spot/misc/version.hh>
#include <spot/misc/minato.hh>
#include <spot/misc/optionmap.hh>
#include <spot/misc/random.hh>
#include <spot/misc/escape.hh>
#include <spot/tl/formula.hh>
#include <spot/tl/environment.hh>
#include <spot/tl/defaultenv.hh>
#include <spot/tl/parse.hh>
#include <spot/twa/bdddict.hh>
#include <spot/tl/apcollect.hh>
#include <spot/tl/dot.hh>
#include <spot/tl/nenoform.hh>
#include <spot/tl/print.hh>
#include <spot/tl/simplify.hh>
#include <spot/tl/unabbrev.hh>
#include <spot/tl/randomltl.hh>
#include <spot/tl/length.hh>
#include <spot/tl/remove_x.hh>
#include <spot/tl/relabel.hh>
#include <spot/twa/bddprint.hh>
#include <spot/twa/fwd.hh>
#include <spot/twa/acc.hh>
#include <spot/twa/twa.hh>
#include <spot/twa/taatgba.hh>
#include <spot/twa/twaproduct.hh>
#include <spot/twaalgos/cleanacc.hh>
#include <spot/twaalgos/degen.hh>
#include <spot/twaalgos/dot.hh>
#include <spot/twaalgos/copy.hh>
#include <spot/twaalgos/complete.hh>
#include <spot/twaalgos/complement.hh>
#include <spot/twaalgos/emptiness.hh>
#include <spot/twaalgos/gtec/gtec.hh>
#include <spot/twaalgos/lbtt.hh>
#include <spot/twaalgos/ltl2taa.hh>
#include <spot/twaalgos/ltl2tgba_fm.hh>
#include <spot/twaalgos/compsusp.hh>
#include <spot/twaalgos/magic.hh>
#include <spot/twaalgos/minimize.hh>
#include <spot/twaalgos/neverclaim.hh>
#include <spot/twaalgos/remfin.hh>
#include <spot/twaalgos/strength.hh>
#include <spot/twaalgos/sccfilter.hh>
#include <spot/twaalgos/stats.hh>
#include <spot/twaalgos/isdet.hh>
#include <spot/twaalgos/isunamb.hh>
#include <spot/twaalgos/simulation.hh>
#include <spot/twaalgos/postproc.hh>
#include <spot/twaalgos/product.hh>
#include <spot/twaalgos/stutter.hh>
#include <spot/twaalgos/translate.hh>
#include <spot/twaalgos/hoa.hh>
#include <spot/twaalgos/dtwasat.hh>
#include <spot/twaalgos/relabel.hh>
#include <spot/parseaut/public.hh>
#include <spot/ta/ta.hh>
#include <spot/ta/tgta.hh>
#include <spot/ta/taexplicit.hh>
#include <spot/ta/tgtaexplicit.hh>
#include <spot/taalgos/tgba2ta.hh>
#include <spot/taalgos/dot.hh>
#include <spot/taalgos/stats.hh>
#include <spot/taalgos/minimize.hh>
using namespace spot;
%}
// Swig come with iterators that implement a decrement method.
// This is not supported in our "successor" iterators.
%fragment("ForwardIterator_T","header",fragment="SwigPyIterator_T") {
namespace swig
{
template<typename OutIterator,
typename ValueType =
typename std::iterator_traits<OutIterator>::value_type,
typename FromOper = from_oper<ValueType> >
class ForwardIterator_T : public SwigPyIterator_T<OutIterator>
{
public:
FromOper from;
typedef OutIterator out_iterator;
typedef ValueType value_type;
typedef SwigPyIterator_T<out_iterator> base;
typedef ForwardIterator_T<OutIterator, ValueType, FromOper> self_type;
ForwardIterator_T(out_iterator curr, out_iterator first,
out_iterator last, PyObject *seq)
: SwigPyIterator_T<OutIterator>(curr, seq), begin(first), end(last)
{
}
PyObject *value() const {
if (base::current == end) {
throw stop_iteration();
} else {
return from(static_cast<const value_type&>(*(base::current)));
}
}
SwigPyIterator *copy() const
{
return new self_type(*this);
}
SwigPyIterator *incr(size_t n = 1)
{
while (n--) {
if (base::current == end) {
throw stop_iteration();
} else {
++base::current;
}
}
return this;
}
private:
out_iterator begin;
out_iterator end;
};
template<typename OutIter>
inline SwigPyIterator*
make_forward_iterator(const OutIter& current,
const OutIter& begin,
const OutIter& end, PyObject *seq = 0)
{
return new ForwardIterator_T<OutIter>(current, begin, end, seq);
}
}
}
%fragment("ForwardIterator_T");
// For spot::emptiness_check_instantiator::construct and any other
// function that return errors via a "char **err" argument.
%typemap(in, numinputs=0) char** OUTPUT (char* temp) {
$1 = &temp;
}
%typemap(argout) char** OUTPUT {
PyObject *obj = SWIG_FromCharPtr(*$1);
if (!$result) {
$result = obj;
//# If the function returns null_ptr (i.e. Py_None), we
//# don't want to override it with OUTPUT as in the
//# default implementation of t_output_helper.
// } else if ($result == Py_None) {
// Py_DECREF($result);
// $result = obj;
} else {
if (!PyList_Check($result)) {
PyObject *o2 = $result;
$result = PyList_New(1);
PyList_SetItem($result, 0, o2);
}
PyList_Append($result, obj);
Py_DECREF(obj);
}
};
%apply char** OUTPUT { char** err };
// This is mainly for acc_cond::is_parity()
%typemap(in, numinputs=0) bool& (bool temp) {
$1 = &temp;
};
%typemap(argout) bool& {
PyObject *obj = SWIG_From_bool(*$1);
if (!$result) {
$result = obj;
} else {
if (!PyList_Check($result)) {
PyObject *o2 = $result;
$result = PyList_New(1);
PyList_SetItem($result, 0, o2);
}
PyList_Append($result, obj);
Py_DECREF(obj);
}
};
// Allow None to be passed for formula. Some functions like
// postprocessor::run() take an optional formula that defaults to
// nullptr. So it make sense to have function that take formulas that
// default to None on the Python side.
%typemap(in) spot::formula {
void *tmp;
int res = SWIG_ConvertPtr($input, &tmp, $descriptor(spot::formula*), 0);
if (!SWIG_IsOK(res)) {
%argument_fail(res, "spot::formula", $symname, $argnum);
}
if (tmp) {
spot::formula* temp = reinterpret_cast< spot::formula * >(tmp);
$1 = *temp;
if (SWIG_IsNewObj(res)) delete temp;
}
// if tmp == nullptr, then the default value of $1 is fine.
}
%typemap(typecheck) spot::formula {
$1 = SWIG_CheckState(SWIG_ConvertPtr($input, nullptr,
$descriptor(spot::formula*), 0));
}
%typemap(out) spot::formula {
if (!$1)
$result = SWIG_Py_Void();
else
$result = SWIG_NewPointerObj(new spot::formula($1), $descriptor(spot::formula*), SWIG_POINTER_OWN);
}
%typemap(out) std::string* {
if (!$1)
$result = SWIG_Py_Void();
else
$result = SWIG_FromCharPtr($1->c_str());
}
%exception {
try {
$action
}
catch (const spot::parse_error& e)
{
std::string er("\n");
er += e.what();
SWIG_exception(SWIG_SyntaxError, er.c_str());
}
catch (const std::invalid_argument& e)
{
SWIG_exception(SWIG_ValueError, e.what());
}
catch (const std::runtime_error& e)
{
SWIG_exception(SWIG_RuntimeError, e.what());
}
}
%include <spot/misc/common.hh>
%include <spot/misc/version.hh>
%include <spot/misc/minato.hh>
%include <spot/misc/optionmap.hh>
%include <spot/misc/random.hh>
%include <spot/misc/escape.hh>
%implicitconv std::vector<spot::formula>;
%include <spot/tl/formula.hh>
namespace std {
%template(liststr) list<std::string>;
%template(vectorformula) vector<spot::formula>;
%template(vectorunsigned) vector<unsigned>;
%template(vectorstring) vector<string>;
%template(atomic_prop_set) set<spot::formula>;
%template(relabeling_map) map<spot::formula, spot::formula>;
}
%include <spot/tl/environment.hh>
%include <spot/tl/defaultenv.hh>
%include <spot/tl/parse.hh>
/* these must come before apcollect.hh */
%include <spot/twa/bdddict.hh>
%include <spot/twa/bddprint.hh>
%include <spot/twa/fwd.hh>
%implicitconv spot::acc_cond::mark_t;
%implicitconv spot::acc_cond::acc_code;
%feature("flatnested") spot::acc_cond::mark_t;
%feature("flatnested") spot::acc_cond::acc_code;
%apply bool* OUTPUT {bool& max, bool& odd};
%include <spot/twa/acc.hh>
%template(pair_bool_mark) std::pair<bool, spot::acc_cond::mark_t>;
%include <spot/twa/twa.hh>
%include <spot/tl/apcollect.hh>
%include <spot/tl/dot.hh>
%include <spot/tl/nenoform.hh>
%include <spot/tl/print.hh>
%include <spot/tl/simplify.hh>
%include <spot/tl/unabbrev.hh>
%include <spot/tl/randomltl.hh>
%include <spot/tl/length.hh>
%include <spot/tl/remove_x.hh>
%include <spot/tl/relabel.hh>
%include <spot/twa/taatgba.hh>
%include <spot/twa/twaproduct.hh>
%include <spot/graph/graph.hh>
%nodefaultctor spot::digraph;
%nodefaultctor spot::internal::state_out;
%traits_swigtype(spot::internal::edge_storage<unsigned int, unsigned int, unsigned int, spot::internal::boxed_label<spot::twa_graph_edge_data, false> >);
%fragment(SWIG_Traits_frag(spot::internal::edge_storage<unsigned int, unsigned int, unsigned int, spot::internal::boxed_label<spot::twa_graph_edge_data, false> >));
%typemap(out, optimal="1") spot::internal::state_out<spot::digraph<spot::twa_graph_state, spot::twa_graph_edge_data>> {
$result = SWIG_NewPointerObj(new $1_ltype($1), $&1_descriptor,
SWIG_POINTER_OWN);
}
%noexception spot::twa_graph::out;
%include <spot/twa/twagraph.hh>
%template(twa_graph_state_out) spot::internal::state_out<spot::digraph<spot::twa_graph_state, spot::twa_graph_edge_data>>;
%template(twa_graph_edge_boxed_data) spot::internal::boxed_label<spot::twa_graph_edge_data, false>;
%template(twa_graph_edge_storage) spot::internal::edge_storage<unsigned int, unsigned int, unsigned int, spot::internal::boxed_label<spot::twa_graph_edge_data, false> >;
// Should come after the definition of twa_graph
%include <spot/twaalgos/cleanacc.hh>
%include <spot/twaalgos/degen.hh>
%include <spot/twaalgos/dot.hh>
%include <spot/twaalgos/copy.hh>
%include <spot/twaalgos/complete.hh>
%include <spot/twaalgos/complement.hh>
%include <spot/twaalgos/emptiness.hh>
%include <spot/twaalgos/gtec/gtec.hh>
%include <spot/twaalgos/lbtt.hh>
%include <spot/twaalgos/ltl2taa.hh>
%include <spot/twaalgos/ltl2tgba_fm.hh>
%include <spot/twaalgos/compsusp.hh>
%include <spot/twaalgos/magic.hh>
%include <spot/twaalgos/minimize.hh>
%include <spot/twaalgos/neverclaim.hh>
%include <spot/twaalgos/remfin.hh>
%include <spot/twaalgos/strength.hh>
%include <spot/twaalgos/sccfilter.hh>
%include <spot/twaalgos/stats.hh>
%include <spot/twaalgos/isdet.hh>
%include <spot/twaalgos/isunamb.hh>
%include <spot/twaalgos/simulation.hh>
%include <spot/twaalgos/postproc.hh>
%include <spot/twaalgos/product.hh>
%include <spot/twaalgos/stutter.hh>
%include <spot/twaalgos/translate.hh>
%include <spot/twaalgos/hoa.hh>
%include <spot/twaalgos/dtwasat.hh>
%include <spot/twaalgos/relabel.hh>
%include <spot/parseaut/public.hh>
%include <spot/ta/ta.hh>
%include <spot/ta/tgta.hh>
%include <spot/ta/taexplicit.hh>
%include <spot/ta/tgtaexplicit.hh>
%include <spot/taalgos/tgba2ta.hh>
%include <spot/taalgos/dot.hh>
%include <spot/taalgos/stats.hh>
%include <spot/taalgos/minimize.hh>
#undef ltl
%exception spot::formula::__getitem__ {
try {
$action
}
catch (const std::runtime_error& e)
{
SWIG_exception(SWIG_IndexError, e.what());
}
}
%extend spot::formula {
// __cmp__ is for Python 2.0
int __cmp__(spot::formula b) { return self->id() - b.id(); }
size_t __hash__() { return self->id(); }
unsigned __len__() { return self->size(); }
formula __getitem__(unsigned pos) { return (*self)[pos]; }
std::string __repr__() { return spot::str_psl(*self); }
std::string _repr_latex_()
{
return std::string("$") + spot::str_sclatex_psl(*self) + '$';
}
std::string __str__() { return spot::str_psl(*self); }
}
%extend spot::bdd_dict {
bool operator==(const spot::bdd_dict& b) const
{
return self == &b;
}
bool operator!=(const spot::bdd_dict& b) const
{
return self != &b;
}
}
%extend spot::twa {
void set_name(std::string name)
{
self->set_named_prop("automaton-name", new std::string(name));
}
std::string* get_name()
{
return self->get_named_prop<std::string>("automaton-name");
}
void set_state_names(std::vector<std::string> names)
{
self->set_named_prop("state-names",
new std::vector<std::string>(std::move(names)));
}
std::vector<std::string>* get_state_names()
{
return self->get_named_prop<std::vector<std::string>>("state-names");
}
}
%extend spot::internal::state_out<spot::digraph<spot::twa_graph_state, spot::twa_graph_edge_data>> {
swig::SwigPyIterator* __iter__(PyObject **PYTHON_SELF)
{
return swig::make_forward_iterator(self->begin(), self->begin(),
self->end(), *PYTHON_SELF);
}
}
%extend spot::acc_cond::acc_code {
std::string __repr__()
{
std::ostringstream os;
os << *self;
return os.str();
}
std::string __str__()
{
std::ostringstream os;
os << *self;
return os.str();
}
}
%extend spot::acc_cond::mark_t {
// http://comments.gmane.org/gmane.comp.programming.swig/14822
mark_t(const std::vector<unsigned>& f)
{
return new spot::acc_cond::mark_t(f.begin(), f.end());
}
std::string __repr__()
{
std::ostringstream os;
os << *self;
return os.str();
}
std::string __str__()
{
std::ostringstream os;
os << *self;
return os.str();
}
}
%extend spot::acc_cond {
std::string __repr__()
{
std::ostringstream os;
os << *self;
return os.str();
}
std::string __str__()
{
std::ostringstream os;
os << *self;
return os.str();
}
}
%extend spot::twa_run {
std::string __str__()
{
std::ostringstream os;
os << *self;
return os.str();
}
}
%nodefaultctor std::ostream;
namespace std {
class ostream {};
class ofstream : public ostream
{
public:
ofstream(const char *fn);
~ofstream();
};
class ostringstream : public ostream
{
public:
ostringstream();
std::string str() const;
~ostringstream();
};
}
%inline %{
bool fnode_instances_check()
{
return spot::fnode::instances_check();
}
spot::parse_error_list
empty_parse_error_list()
{
parse_error_list l;
return l;
}
spot::parse_aut_error_list
empty_parse_aut_error_list()
{
parse_aut_error_list l;
return l;
}
spot::twa_graph_ptr
ensure_digraph(const spot::twa_ptr& a)
{
auto aa = std::dynamic_pointer_cast<spot::twa_graph>(a);
if (aa)
return aa;
return spot::make_twa_graph(a, spot::twa::prop_set::all());
}
std::ostream&
get_cout()
{
return std::cout;
}
void
nl_cout()
{
std::cout << std::endl;
}
std::ostream&
get_cerr()
{
return std::cerr;
}
void
nl_cerr()
{
std::cerr << std::endl;
}
void
print_on(std::ostream& on, const std::string& what)
{
on << what;
}
int
unblock_signal(int signum)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, signum);
return sigprocmask(SIG_UNBLOCK, &set, 0);
}
%}
%extend spot::parse_error_list {
bool
__nonzero__()
{
return !self->empty();
}
bool
__bool__()
{
return !self->empty();
}
}
%extend spot::parse_aut_error_list {
bool
__nonzero__()
{
return !self->empty();
}
bool
__bool__()
{
return !self->empty();
}
}

3
python/tests/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
Makefile
Makefile.in
run

67
python/tests/Makefile.am Normal file
View file

@ -0,0 +1,67 @@
## -*- coding: utf-8 -*-
## Copyright (C) 2010, 2012, 2013, 2014, 2015 Labortatoire de
## Recherche et Développement de l'EPITA.
## Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
## et Marie Curie.
##
## This file is part of Spot, a model checking library.
##
## Spot is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## Spot is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
## License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
EXTRA_DIST = \
$(TESTS) \
ltl2tgba.py \
ipnbdoctest.py
LOG_COMPILER = ./run
LOG_DRIVER = $(TEST_LOG_DRIVER)
# ensure run is rebuilt before the tests are run.
check_SCRIPTS = run
TESTS = \
acc_cond.ipynb \
accparse.ipynb \
accparse2.py \
alarm.py \
automata.ipynb \
automata-io.ipynb \
bddnqueen.py \
decompose.ipynb \
formulas.ipynb \
implies.py \
interdep.py \
ltl2tgba.test \
ltlparse.py \
ltlsimple.py \
minato.py \
optionmap.py \
parsetgba.py \
piperead.ipynb \
product.ipynb \
randaut.ipynb \
randgen.py \
randltl.ipynb \
relabel.py \
remfin.py \
satmin.py \
setxor.py \
testingaut.ipynb
SUFFIXES = .ipynb .html
.ipynb.html:
$(IPYTHON) nbconvert $< --to html
.PHONY: nb-html
nb-html: $(TESTS:.ipynb=.html)

1444
python/tests/acc_cond.ipynb Normal file

File diff suppressed because it is too large Load diff

177
python/tests/accparse.ipynb Normal file
View file

@ -0,0 +1,177 @@
{
"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.4.3+"
},
"name": "",
"signature": "sha256:1ee7951bed30652ae110a14b210541829221552eb944ff01f25236179673dd5b"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": true,
"input": [
"import spot\n",
"spot.setup()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"c = spot.acc_code('Inf(0)&Fin(1)|Inf(2)&Fin(3)'); c"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 2,
"text": [
"(Fin(1) & Inf(0)) | (Fin(3) & Inf(2))"
]
}
],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"c.to_dnf()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"text": [
"(Fin(1) & Inf(0)) | (Fin(3) & Inf(2))"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"c.to_cnf()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"text": [
"(Inf(0) | Inf(2)) & (Fin(3) | Inf(0)) & (Fin(1) | Inf(2)) & (Fin(1)|Fin(3))"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for acc in ['all', 't', \n",
" 'Buchi', 'generalized-Buchi 3', 'generalized-Buchi 0',\n",
" 'co-Buchi', 'generalized-co-Buchi 3', 'generalized-co-Buchi 0',\n",
" 'Rabin 2', 'Rabin 0',\n",
" 'Streett 2', 'Streett 0',\n",
" 'generalized-Rabin 3 1 2 3', 'generalized-Rabin 0',\n",
" 'parity min even 6', 'parity max odd 6', 'parity max even 6', 'parity min odd 6',\n",
" 'parity min even 5', 'parity max odd 5', 'parity max even 5', 'parity min odd 5',\n",
" 'parity min even 2', 'parity max odd 2', 'parity max even 2', 'parity min odd 2',\n",
" 'parity min even 1', 'parity max odd 1', 'parity max even 1', 'parity min odd 1',\n",
" 'parity min even 0', 'parity max odd 0', 'parity max even 0', 'parity min odd 0',\n",
" ]:\n",
" print(acc, ': ', spot.acc_code(acc), sep='')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"all: t\n",
"t: t\n",
"Buchi: Inf(0)\n",
"generalized-Buchi 3: Inf(0)&Inf(1)&Inf(2)\n",
"generalized-Buchi 0: t\n",
"co-Buchi: Fin(0)\n",
"generalized-co-Buchi 3: Fin(0)|Fin(1)|Fin(2)\n",
"generalized-co-Buchi 0: f\n",
"Rabin 2: (Fin(0) & Inf(1)) | (Fin(2) & Inf(3))\n",
"Rabin 0: f\n",
"Streett 2: (Fin(0) | Inf(1)) & (Fin(2) | Inf(3))\n",
"Streett 0: t\n",
"generalized-Rabin 3 1 2 3: (Fin(0) & Inf(1)) | (Fin(2) & (Inf(3)&Inf(4))) | (Fin(5) & (Inf(6)&Inf(7)&Inf(8)))\n",
"generalized-Rabin 0: f\n",
"parity min even 6: Inf(0) | (Fin(1) & (Inf(2) | (Fin(3) & (Inf(4) | Fin(5)))))\n",
"parity max odd 6: Inf(5) | (Fin(4) & (Inf(3) | (Fin(2) & (Inf(1) | Fin(0)))))\n",
"parity max even 6: Fin(5) & (Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0)))))\n",
"parity min odd 6: Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | (Fin(4) & Inf(5)))))\n",
"parity min even 5: Inf(0) | (Fin(1) & (Inf(2) | (Fin(3) & Inf(4))))\n",
"parity max odd 5: Fin(4) & (Inf(3) | (Fin(2) & (Inf(1) | Fin(0))))\n",
"parity max even 5: Inf(4) | (Fin(3) & (Inf(2) | (Fin(1) & Inf(0))))\n",
"parity min odd 5: Fin(0) & (Inf(1) | (Fin(2) & (Inf(3) | Fin(4))))\n",
"parity min even 2: Inf(0) | Fin(1)\n",
"parity max odd 2: Inf(1) | Fin(0)\n",
"parity max even 2: Fin(1) & Inf(0)\n",
"parity min odd 2: Fin(0) & Inf(1)\n",
"parity min even 1: Inf(0)\n",
"parity max odd 1: Fin(0)\n",
"parity max even 1: Inf(0)\n",
"parity min odd 1: Fin(0)\n",
"parity min even 0: t\n",
"parity max odd 0: t\n",
"parity max even 0: f\n",
"parity min odd 0: f\n"
]
}
],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
}
],
"metadata": {}
}
]
}

93
python/tests/accparse2.py Normal file
View file

@ -0,0 +1,93 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2015 Laboratoire de Recherche et Développement
# de l'Epita
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
a = spot.acc_cond(5)
a.set_acceptance(spot.acc_code('parity min odd 5'))
assert(a.is_parity() == [True, False, True])
a.set_acceptance('parity max even 5')
assert(a.is_parity() == [True, True, False])
a.set_acceptance('generalized-Buchi 5')
assert(a.is_parity()[0] == False)
assert(a.is_parity(True)[0] == False)
a.set_acceptance('Inf(4) | (Fin(3)&Inf(2)) | (Fin(3)&Fin(1)&Inf(0))')
assert(a.is_parity()[0] == False)
assert(a.is_parity(True) == [True, True, False])
a = spot.acc_cond(0)
a.set_acceptance('all')
assert(a.is_rabin() == -1)
assert(a.is_streett() == 0)
assert(a.is_parity() == [True, True, True])
a.set_acceptance('none')
assert(a.is_rabin() == 0)
assert(a.is_streett() == -1)
assert(a.is_parity() == [True, True, False])
a = spot.acc_cond('(Fin(0)&Inf(1))')
assert(a.is_rabin() == 1)
assert(a.is_streett() == -1)
a.set_acceptance('Inf(1)&Fin(0)')
assert(a.is_rabin() == 1)
assert(a.is_streett() == -1)
a.set_acceptance('(Fin(0)|Inf(1))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == 1)
a.set_acceptance('Inf(1)|Fin(0)')
assert(a.is_rabin() == -1)
assert(a.is_streett() == 1)
a = spot.acc_cond('(Fin(0)&Inf(1))|(Fin(2)&Inf(3))')
assert(a.is_rabin() == 2)
assert(a.is_streett() == -1)
a.set_acceptance(spot.acc_code('(Inf(3)&Fin(2))|(Fin(0)&Inf(1))'))
assert(a.is_rabin() == 2)
assert(a.is_streett() == -1)
a.set_acceptance(spot.acc_code('(Inf(2)&Fin(3))|(Fin(0)&Inf(1))'))
assert(a.is_rabin() == -1)
assert(a.is_streett() == -1)
a.set_acceptance(spot.acc_code('(Inf(3)&Fin(2))|(Fin(2)&Inf(1))'))
assert(a.is_rabin() == -1)
assert(a.is_streett() == -1)
a.set_acceptance(spot.acc_code('(Inf(1)&Fin(0))|(Fin(0)&Inf(1))'))
assert(a.is_rabin() == -1)
assert(a.is_streett() == -1)
a.set_acceptance('(Fin(0)&Inf(1))|(Inf(1)&Fin(0))|(Inf(3)&Fin(2))')
assert(a.is_rabin() == 2)
assert(a.is_streett() == -1)
a.set_acceptance('(Fin(0)|Inf(1))&(Fin(2)|Inf(3))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == 2)
a.set_acceptance('(Inf(3)|Fin(2))&(Fin(0)|Inf(1))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == 2)
a.set_acceptance('(Inf(2)|Fin(3))&(Fin(0)|Inf(1))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == -1)
a.set_acceptance('(Inf(3)|Fin(2))&(Fin(2)|Inf(1))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == -1)
a.set_acceptance('(Inf(1)|Fin(0))&(Fin(0)|Inf(1))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == -1)
a.set_acceptance('(Fin(0)|Inf(1))&(Inf(1)|Fin(0))&(Inf(3)|Fin(2))')
assert(a.is_rabin() == -1)
assert(a.is_streett() == 2)

66
python/tests/alarm.py Executable file
View file

@ -0,0 +1,66 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2012, 2014, 2015 Laboratoire de Recherche et Développement
# de l'Epita
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
import time
import signal
import sys
import os
def alarm_handler(signum, frame):
sys.stdout.write("signaled\n")
os.kill(child, signal.SIGTERM)
exit(0)
f = """!(G(F(P_Rbt2.observe)&& F(P_Rbt3.observe) &&
F(P_rbt1.observe)&& F(P_Rbt1.plus || P_Rbt1.moins || P_Rbt1.stop)&&
F(P_Rbt3.plus || P_Rbt3.moins || P_Rbt3.stop) && F(P_Rbt2.plus ||
P_Rbt2.moins || P_Rbt2.stop))-> G((F "map[0]==1") && (F "map[1]==1")
&& (F "map[2]==1") && (F "map[3]==1") && (F "map[4]==1") && (F
"map[5]==1") && (F "map[6]==1") && (F "map[7]==1") && (F "map[8]==1")
&& (F "map[9]==1") && (F "map[0]==2") && (F "map[1]==2") && (F
"map[2]==2") && (F "map[3]==2") && (F "map[4]==2") && (F "map[5]==2")
&& (F "map[6]==2") && (F "map[7]==2") && (F "map[8]==2") && (F
"map[9]==2") && (F "map[0]==3") && (F "map[1]==3") && (F "map[2]==3")
&& (F "map[3]==3") && (F "map[4]==3") && (F "map[5]==3") && (F
"map[6]==3") && (F "map[7]==3") && (F "map[8]==3") && (F
"map[9]==3")))"""
e = spot.default_environment.instance()
p = spot.empty_parse_error_list()
f = spot.parse_infix_psl(f, p, e)
d = spot.make_bdd_dict()
spot.unblock_signal(signal.SIGALRM)
spot.unblock_signal(signal.SIGTERM)
os.setpgrp()
child = os.fork()
if child != 0:
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(2)
os.waitpid(child, 0)
# If the child returns, before we get the alarm it's a bug.
exit(1)
# This is expected to take WAY more that 2s.
print("Before")
spot.ltl_to_tgba_fm(f, d, True)
print("After")
exit(1)

View file

@ -0,0 +1,862 @@
{
"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.4.3+"
},
"name": "",
"signature": "sha256:79ee85572b2a0147d88b2d3d355977e3f34dadb82bd7e8589bdbb2cf2a539b0b"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.display import display\n",
"import spot\n",
"spot.setup()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"a = spot.translate('a U b')\n",
"for fmt in ('hoa', 'spin', 'dot', 'lbtt'):\n",
" print(a.to_str(fmt))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"HOA: v1\n",
"States: 2\n",
"Start: 1\n",
"AP: 2 \"a\" \"b\"\n",
"acc-name: Buchi\n",
"Acceptance: 1 Inf(0)\n",
"properties: trans-labels explicit-labels state-acc deterministic\n",
"properties: stutter-invariant terminal\n",
"--BODY--\n",
"State: 0 {0}\n",
"[t] 0\n",
"State: 1\n",
"[1] 0\n",
"[0&!1] 1\n",
"--END--\n",
"never {\n",
"T0_init:\n",
" if\n",
" :: (b) -> goto accept_all\n",
" :: ((a) && (!(b))) -> goto T0_init\n",
" fi;\n",
"accept_all:\n",
" skip\n",
"}\n",
"\n",
"digraph G {\n",
" rankdir=LR\n",
" node [shape=\"circle\"]\n",
" fontname=\"Lato\"\n",
" node [fontname=\"Lato\"]\n",
" edge [fontname=\"Lato\"]\n",
" size=\"10.2,5\" node[style=filled,fillcolor=\"#ffffaa\"] edge[arrowhead=vee, arrowsize=.7]\n",
" I [label=\"\", style=invis, width=0]\n",
" I -> 1\n",
" 0 [label=\"0\", peripheries=2]\n",
" 0 -> 0 [label=<1>]\n",
" 1 [label=\"1\"]\n",
" 1 -> 0 [label=<b>]\n",
" 1 -> 1 [label=<a &amp; !b>]\n",
"}\n",
"\n",
"2 1\n",
"0 1 -1\n",
"1 \"b\"\n",
"0 & \"a\" ! \"b\"\n",
"-1\n",
"1 0 0 -1\n",
"1 t\n",
"-1\n",
"\n"
]
}
],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"a.save('example.aut').save('example.aut', format='lbtt', append=True)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f4414147600> >"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!cat example.aut"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"HOA: v1\r\n",
"States: 2\r\n",
"Start: 1\r\n",
"AP: 2 \"a\" \"b\"\r\n",
"acc-name: Buchi\r\n",
"Acceptance: 1 Inf(0)\r\n",
"properties: trans-labels explicit-labels state-acc deterministic\r\n",
"properties: stutter-invariant terminal\r\n",
"--BODY--\r\n",
"State: 0 {0}\r\n",
"[t] 0\r\n",
"State: 1\r\n",
"[1] 0\r\n",
"[0&!1] 1\r\n",
"--END--\r\n",
"2 1\r\n",
"0 1 -1\r\n",
"1 \"b\"\r\n",
"0 & \"a\" ! \"b\"\r\n",
"-1\r\n",
"1 0 0 -1\r\n",
"1 t\r\n",
"-1\r\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for a in spot.automata('example.aut'):\n",
" display(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f4414157570> >"
]
},
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f4414157660> >"
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Test `--ABORT--`\n",
"----------------"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file example.aut\n",
"HOA: v1\n",
"States: 2\n",
"Start: 1\n",
"AP: 2 \"a\" \"b\"\n",
"acc-name: Buchi\n",
"Acceptance: 1 Inf(0)\n",
"--BODY--\n",
"State: 0 {0}\n",
"[t] 0\n",
"--ABORT-- /* the previous automaton should be ignored */\n",
"HOA: v1\n",
"States: 2\n",
"Start: 1\n",
"AP: 2 \"a\" \"b\"\n",
"Acceptance: 1 Inf(0)\n",
"--BODY--\n",
"State: 0 {0}\n",
"[t] 0\n",
"State: 1\n",
"[1] 0\n",
"[0&!1] 1\n",
"--END--"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting example.aut\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for a in spot.automata('example.aut'):\n",
" display(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f441765be40> >"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for a in spot.automata(\"\"\"\n",
"HOA: v1\n",
"States: 2\n",
"Start: 1\n",
"name: \"Hello world\"\n",
"AP: 2 \"a\" \"b\"\n",
"Acceptance: 1 Inf(0)\n",
"--BODY--\n",
"State: 0 {0}\n",
"[t] 0\n",
"State: 1\n",
"[1] 0\n",
"[0&!1] 1\n",
"--END--\n",
"HOA: v1\n",
"States: 1\n",
"Start: 0\n",
"name: \"Hello world 2\"\n",
"AP: 2 \"a\" \"b\"\n",
"Acceptance: 2 Inf(0)&Inf(1)\n",
"--BODY--\n",
"State: 0 {0}\n",
"[t] 0 {1}\n",
"[0&!1] 0\n",
"--END--\n",
"\"\"\"):\n",
" display(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f4414157690> >"
]
},
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"83pt\" height=\"138pt\"\n",
" viewBox=\"0.00 0.00 82.50 138.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 134)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-134 78.5,-134 78.5,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" 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\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-18C2.79388,-18 17.1543,-18 30.6317,-18\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-18 30.9419,-21.1501 34.4419,-18 30.9419,-18.0001 30.9419,-18.0001 30.9419,-18.0001 34.4419,-18 30.9418,-14.8501 37.9419,-18 37.9419,-18\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M52.7643,-35.7817C52.2144,-45.3149 53.293,-54 56,-54 57.988,-54 59.0977,-49.3161 59.3292,-43.0521\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"59.2357,-35.7817 62.4756,-42.7406 59.2808,-39.2814 59.3258,-42.7812 59.3258,-42.7812 59.3258,-42.7812 59.2808,-39.2814 56.1761,-42.8217 59.2357,-35.7817 59.2357,-35.7817\"/>\n",
"<text text-anchor=\"start\" x=\"51.5\" y=\"-71.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"<text text-anchor=\"start\" x=\"40\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#5da5da\">\u24ff</text>\n",
"<text text-anchor=\"start\" x=\"56\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#f17cb0\">\u2776</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M50.9375,-35.5938C47.5625,-56.125 49.25,-82 56,-82 61.9854,-82 63.9902,-61.6553 62.0146,-42.7315\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"61.0625,-35.5938 65.1104,-42.1158 61.5253,-39.063 61.9881,-42.5323 61.9881,-42.5323 61.9881,-42.5323 61.5253,-39.063 58.8657,-42.9488 61.0625,-35.5938 61.0625,-35.5938\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-100.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"<text text-anchor=\"start\" x=\"48\" y=\"-85.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#5da5da\">\u24ff</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f441765be40> >"
]
}
],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Test syntax errors\n",
"------------------"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file example.aut\n",
"HOA: v1\n",
"States: 2\n",
"Start: 1\n",
"AP: 2 \"a\" \"b\"\n",
"acc-name: Buchi\n",
"Acceptance: 1 Inf(0)\n",
"--BODY--\n",
"State: 0 {0}\n",
"[t] 1\n",
"State: 1\n",
"[t] 1\n",
"--END--\n",
"HOA: v1\n",
"States: 2\n",
"Start: 1\n",
"AP: 2 \"a\" \"b\"\n",
"Acceptance: 1 Inf(0)\n",
"--BODY--\n",
"State: 0 {0}\n",
"[a] 3\n",
"State: 1\n",
"[1] 0\n",
"[0&!1] 1\n",
"--END--"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting example.aut\n"
]
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for a in spot.automata('example.aut'):\n",
" display(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"133pt\" height=\"101pt\"\n",
" viewBox=\"0.00 0.00 133.00 101.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 97)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-97 129,-97 129,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"107\" cy=\"-42\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"107\" y=\"-38.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M23.0602,-62.9848C24.6706,-62.5773 58.2688,-54.0766 82.2014,-48.0213\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"89.2724,-46.2323 83.2589,-51.0031 85.8793,-47.0908 82.4862,-47.9493 82.4862,-47.9493 82.4862,-47.9493 85.8793,-47.0908 81.7135,-44.8956 89.2724,-46.2323 89.2724,-46.2323\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M99.9688,-58.6641C98.4062,-68.625 100.75,-78 107,-78 111.688,-78 114.178,-72.7266 114.471,-65.8876\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"114.031,-58.6641 117.601,-65.4598 114.244,-62.1576 114.456,-65.6511 114.456,-65.6511 114.456,-65.6511 114.244,-62.1576 111.312,-65.8425 114.031,-58.6641 114.031,-58.6641\"/>\n",
"<text text-anchor=\"middle\" x=\"107\" y=\"-81.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"22\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"22\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"22\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M43.5169,-26.9438C55.3149,-29.7867 70.1833,-33.3695 82.4561,-36.3268\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"89.3394,-37.9854 81.7962,-39.4079 85.9368,-37.1655 82.5342,-36.3455 82.5342,-36.3455 82.5342,-36.3455 85.9368,-37.1655 83.2721,-33.2832 89.3394,-37.9854 89.3394,-37.9854\"/>\n",
"<text text-anchor=\"middle\" x=\"66.5\" y=\"-37.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f44141578d0> >"
]
},
{
"ename": "SyntaxError",
"evalue": "\nexample.aut:20.2: syntax error, unexpected identifier\nexample.aut:20.1-3: ignoring this invalid label\nexample.aut:20.5: state number is larger than state count...\nexample.aut:14.1-9: ... declared here.\n (<string>)",
"output_type": "pyerr",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<string>\"\u001b[0;36m, line \u001b[0;32munknown\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m \nexample.aut:20.2: syntax error, unexpected identifier\nexample.aut:20.1-3: ignoring this invalid label\nexample.aut:20.5: state number is larger than state count...\nexample.aut:14.1-9: ... declared here.\n\n"
]
}
],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.automaton('example.aut', timeout=100)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 11,
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"133pt\" height=\"101pt\"\n",
" viewBox=\"0.00 0.00 133.00 101.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 97)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-97 129,-97 129,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"107\" cy=\"-42\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"107\" y=\"-38.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M23.0602,-62.9848C24.6706,-62.5773 58.2688,-54.0766 82.2014,-48.0213\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"89.2724,-46.2323 83.2589,-51.0031 85.8793,-47.0908 82.4862,-47.9493 82.4862,-47.9493 82.4862,-47.9493 85.8793,-47.0908 81.7135,-44.8956 89.2724,-46.2323 89.2724,-46.2323\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M99.9688,-58.6641C98.4062,-68.625 100.75,-78 107,-78 111.688,-78 114.178,-72.7266 114.471,-65.8876\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"114.031,-58.6641 117.601,-65.4598 114.244,-62.1576 114.456,-65.6511 114.456,-65.6511 114.456,-65.6511 114.244,-62.1576 111.312,-65.8425 114.031,-58.6641 114.031,-58.6641\"/>\n",
"<text text-anchor=\"middle\" x=\"107\" y=\"-81.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"22\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"22\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"22\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M43.5169,-26.9438C55.3149,-29.7867 70.1833,-33.3695 82.4561,-36.3268\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"89.3394,-37.9854 81.7962,-39.4079 85.9368,-37.1655 82.5342,-36.3455 82.5342,-36.3455 82.5342,-36.3455 85.9368,-37.1655 83.2721,-33.2832 89.3394,-37.9854 89.3394,-37.9854\"/>\n",
"<text text-anchor=\"middle\" x=\"66.5\" y=\"-37.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f44141578a0> >"
]
}
],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.automaton('non-existing-cmd |')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "CalledProcessError",
"evalue": "Command 'non-existing-cmd ' returned non-zero exit status 127",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-12-2b2d1b66dcd6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'non-existing-cmd |'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 404\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 405\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 406\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 407\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 408\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, *sources)\u001b[0m\n\u001b[1;32m 395\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 396\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 397\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 398\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mCalledProcessError\u001b[0m: Command 'non-existing-cmd ' returned non-zero exit status 127"
]
}
],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.automaton('sleep 3; cat example.aut |', timeout=1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "TimeoutExpired",
"evalue": "Command 'sleep 3; cat example.aut ' timed out after 1 seconds",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTimeoutExpired\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-13-d9c814f4e517>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'sleep 3; cat example.aut |'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 404\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 405\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 406\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 407\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 408\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, *sources)\u001b[0m\n\u001b[1;32m 366\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 367\u001b[0m out = subprocess.check_output(filename[:-1], shell=True,\n\u001b[0;32m--> 368\u001b[0;31m timeout=timeout)\n\u001b[0m\u001b[1;32m 369\u001b[0m \u001b[0mp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mautomaton_stream_parser\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 370\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0;34m'\\n'\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/lib/python3.4/subprocess.py\u001b[0m in \u001b[0;36mcheck_output\u001b[0;34m(timeout, *popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 611\u001b[0m \u001b[0mprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkill\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 612\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0munused_err\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcommunicate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 613\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTimeoutExpired\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0moutput\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 614\u001b[0m \u001b[0;32mexcept\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 615\u001b[0m \u001b[0mprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkill\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTimeoutExpired\u001b[0m: Command 'sleep 3; cat example.aut ' timed out after 1 seconds"
]
}
],
"prompt_number": 13
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"rm example.aut"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
}
],
"metadata": {}
}
]
}

3175
python/tests/automata.ipynb Normal file

File diff suppressed because it is too large Load diff

107
python/tests/bddnqueen.py Executable file
View file

@ -0,0 +1,107 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2010, 2011, 2012, 2014 Laboratoire de Recherche et
# Développement de l'EPITA.
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6
# (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
# Pierre et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Python translation of the C++ example from the BuDDy distribution.
# (compare with buddy/examples/queen/queen.cxx)
import sys
from buddy import *
# Build the requirements for all other fields than (i,j) assuming
# that (i,j) has a queen.
def build(i, j):
a = b = c = d = bddtrue
# No one in the same column.
for l in side:
if l != j:
a &= X[i][j] >> -X[i][l]
# No one in the same row.
for k in side:
if k != i:
b &= X[i][j] >> -X[k][j]
# No one in the same up-right diagonal.
for k in side:
ll = k - i + j
if ll >= 0 and ll < N:
if k != i:
c &= X[i][j] >> -X[k][ll]
# No one in the same down-right diagonal.
for k in side:
ll = i + j - k
if ll >= 0 and ll < N:
if k != i:
c &= X[i][j] >> -X[k][ll]
global queen
queen &= a & b & c & d
# Get the number of queens from the command-line, or default to 8.
if len(sys.argv) > 1:
N = int(argv[1])
else:
N = 8
side = range(N)
# Initialize with 100000 nodes, 10000 cache entries and NxN variables.
bdd_init(N * N * 256, 10000)
bdd_setvarnum(N * N)
queen = bddtrue
# Build variable array.
X = [[bdd_ithvar(i*N+j) for j in side] for i in side]
# Place a queen in each row.
for i in side:
e = bddfalse
for j in side:
e |= X[i][j]
queen &= e
# Build requirements for each variable(field).
for i in side:
for j in side:
sys.stdout.write("Adding position %d, %d\n" % (i, j))
build(i, j)
# Print the results.
sys.stdout.write("There are %d solutions, one is:\n" %
bdd_satcount(queen))
solution = bdd_satone(queen)
bdd_printset(solution)
from spot import nl_cout
nl_cout()
# Cleanup all BDD variables before calling bdd_done(), otherwise
# bdd_delref will be called after bdd_done() and this is unsafe in
# optimized builds.
X = e = queen = solution = 0
bdd_done()

5010
python/tests/decompose.ipynb Normal file

File diff suppressed because it is too large Load diff

727
python/tests/formulas.ipynb Normal file
View file

@ -0,0 +1,727 @@
{
"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.4.3+"
},
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Handling LTL and PSL formulas\n",
"============================="
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import spot"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For interactive use, formulas can be entered as text strings and passed to the `spot.formula` constructor."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.formula('p1 U p2 R (p3 & !p4)')\n",
"f"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 2,
"text": [
"p1 U (p2 R (p3 & !p4))"
]
}
],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"g = spot.formula('{a;b*;c[+]}<>->GFb'); g"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$\\{a \\mathbin{\\mathsf{;}} b^{\\star} \\mathbin{\\mathsf{;}} c^+\\}\\mathrel{\\Diamond\\kern-1.7pt\\raise.4pt\\hbox{$\\mathord{\\rightarrow}$}} \\mathsf{G} \\mathsf{F} b$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"text": [
"{a;b[*];c[+]}<>-> GFb"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default the parser recognizes an infix syntax, but when this fails, it tries to read the formula with the [LBT](http://www.tcs.hut.fi/Software/maria/tools/lbt/) syntax:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"h = spot.formula('& | a b c'); h"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$c \\land (a \\lor b)$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"text": [
"c & (a | b)"
]
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default, a formula object is presented using mathjax as above.\n",
"When a formula is converted to string you get Spot's syntax by default:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"str(f)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 5,
"text": [
"'p1 U (p2 R (p3 & !p4))'"
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you prefer to print the string in another syntax, you may use the `to_str()` method, with an argument that indicates the output format to use. The `latex` format assumes that you will the define macros such as `\\U`, `\\R` to render all operators as you wish. On the otherhand, the `sclatex` (with `sc` for self-contained) format hard-codes the rendering of each of those operators: this is typically the output that is used to render formulas using MathJax in a notebook. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for i in ['spot', 'spin', 'lbt', 'wring', 'utf8', 'latex', 'sclatex']:\n",
" print(\"%-10s%s\" % (i, f.to_str(i)))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"spot p1 U (p2 R (p3 & !p4))\n",
"spin p1 U (p2 V (p3 && !p4))\n",
"lbt U p1 V p2 & p3 ! p4\n",
"wring (p1=1) U ((p2=1) R ((p3=1) * (p4=0)))\n",
"utf8 p1 U (p2 R (p3\u2227\u00acp4))\n",
"latex p_{1} \\U (p_{2} \\R (p_{3} \\land \\lnot p_{4}))\n",
"sclatex p_{1} \\mathbin{\\mathsf{U}} (p_{2} \\mathbin{\\mathsf{R}} (p_{3} \\land \\lnot p_{4}))\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Formulas output via `format()` can also use some convenient shorthand to select the syntax:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(\"\"\"\\\n",
"Spin: {0:s}\n",
"Spin+parentheses: {0:sp}\n",
"Spot (default): {0}\n",
"Spot+shell quotes: {0:q}\n",
"LBT, right aligned: {0:l:~>40}\"\"\".format(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Spin: p1 U (p2 V (p3 && !p4))\n",
"Spin+parentheses: (p1) U ((p2) V ((p3) && (!(p4))))\n",
"Spot (default): p1 U (p2 R (p3 & !p4))\n",
"Spot+shell quotes: 'p1 U (p2 R (p3 & !p4))'\n",
"LBT, right aligned: ~~~~~~~~~~~~~~~~~~~~~U p1 V p2 & p3 ! p4\n"
]
}
],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The specifiers that can be used with `format` are documented as follows:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"help(spot.formula.__format__)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on function __format__ in module spot:\n",
"\n",
"__format__(self, spec)\n",
" Format the formula according to `spec`.\n",
" \n",
" Parameters\n",
" ----------\n",
" spec : str, optional\n",
" a list of letters that specify how the formula\n",
" should be formatted.\n",
" \n",
" Supported specifiers\n",
" --------------------\n",
" \n",
" - 'f': use Spot's syntax (default)\n",
" - '8': use Spot's syntax in UTF-8 mode\n",
" - 's': use Spin's syntax\n",
" - 'l': use LBT's syntax\n",
" - 'w': use Wring's syntax\n",
" - 'x': use LaTeX output\n",
" - 'X': use self-contained LaTeX output\n",
" \n",
" Add some of those letters for additional options:\n",
" \n",
" - 'p': use full parentheses\n",
" - 'c': escape the formula for CSV output (this will\n",
" enclose the formula in double quotes, and escape\n",
" any included double quotes)\n",
" - 'h': escape the formula for HTML output\n",
" - 'd': escape double quotes and backslash,\n",
" for use in C-strings (the outermost double\n",
" quotes are *not* added)\n",
" - 'q': quote and escape for shell output, using single\n",
" quotes or double quotes depending on the contents.\n",
" \n",
" - ':spec': pass the remaining specification to the\n",
" formating function for strings.\n",
"\n"
]
}
],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A `spot.formula` object has a number of built-in predicates whose value have been computed when the formula was constructed. For instance you can check whether a formula is in negative normal form using `is_in_nenoform()`, and you can make sure it is an LTL formula (i.e. not a PSL formula) using `is_ltl_formula()`:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f.is_in_nenoform() and f.is_ltl_formula()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 9,
"text": [
"True"
]
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"g.is_ltl_formula()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 10,
"text": [
"False"
]
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly, `is_syntactic_stutter_invariant()` tells wether the structure of the formula guarranties it to be stutter invariant. For LTL formula, this means the `X` operator should not be used. For PSL formula, this function capture all formulas built using the [siPSL grammar](http://www.daxc.de/eth/paper/09atva.pdf)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f.is_syntactic_stutter_invariant()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 11,
"text": [
"True"
]
}
],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.formula('{a[*];b}<>->c').is_syntactic_stutter_invariant()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 12,
"text": [
"False"
]
}
],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.formula('{a[+];b[*]}<>->d').is_syntactic_stutter_invariant()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 13,
"text": [
"True"
]
}
],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`spot.relabel` renames the atomic propositions that occur in a formula, using either letters, or numbered propositions:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"gf = spot.formula('(GF_foo_) && \"a > b\" && \"proc[2]@init\"'); gf"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$``\\mathit{a > b}\\textrm{''} \\land ``\\mathit{proc[2]@init}\\textrm{''} \\land \\mathsf{G} \\mathsf{F} \\mathit{\\_foo\\_}$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 14,
"text": [
"\"a > b\" & \"proc[2]@init\" & GF_foo_"
]
}
],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.relabel(gf, spot.Abc)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$a \\land b \\land \\mathsf{G} \\mathsf{F} c$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 15,
"text": [
"a & b & GFc"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.relabel(gf, spot.Pnn)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$p_{0} \\land p_{1} \\land \\mathsf{G} \\mathsf{F} p_{2}$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 16,
"text": [
"p0 & p1 & GFp2"
]
}
],
"prompt_number": 16
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The AST of any formula can be displayed with `show_ast()`. Despite the name, this is not a tree but a DAG, because identical subtrees are merged. Binary operators have their left and right operands denoted with `L` and `R`, while non-commutative n-ary operators have their operands numbered."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(g); g.show_ast()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{a;b[*];c[+]}<>-> GFb\n"
]
},
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 17,
"svg": [
"<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=\"white\" points=\"-4,4 -4,-256 265,-256 265,4 -4,4\" stroke=\"none\"/>\n",
"<!-- 0 -->\n",
"<g class=\"node\" id=\"node1\"><title>0</title>\n",
"<ellipse cx=\"106\" cy=\"-234\" fill=\"none\" rx=\"40.8928\" ry=\"18\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"106\" y=\"-230.3\">EConcat</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g class=\"node\" id=\"node2\"><title>1</title>\n",
"<ellipse cx=\"155\" cy=\"-162\" fill=\"none\" rx=\"35.9954\" ry=\"18\" stroke=\"black\"/>\n",
"<text 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\"><title>0-&gt;1</title>\n",
"<path d=\"M117.612,-216.411C123.593,-207.868 131.005,-197.278 137.649,-187.787\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"140.604,-189.669 143.471,-179.47 134.869,-185.655 140.604,-189.669\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"113.112\" y=\"-205.211\">L</text>\n",
"</g>\n",
"<!-- 7 -->\n",
"<g class=\"node\" id=\"node8\"><title>7</title>\n",
"<ellipse cx=\"58\" cy=\"-162\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
"<text 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\"><title>0-&gt;7</title>\n",
"<path d=\"M94.6247,-216.411C88.6815,-207.744 81.2945,-196.971 74.7146,-187.375\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"77.5052,-185.256 68.9633,-178.988 71.732,-189.215 77.5052,-185.256\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"89.6247\" y=\"-205.211\">R</text>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g class=\"node\" id=\"node3\"><title>2</title>\n",
"<polygon fill=\"none\" points=\"261,-36 207,-36 207,-0 261,-0 261,-36\" stroke=\"black\"/>\n",
"<text 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\"><title>1-&gt;2</title>\n",
"<path d=\"M173.171,-146.485C184.356,-136.683 198.19,-122.858 207,-108 218.359,-88.8432 225.316,-64.4933 229.316,-46.1073\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"232.797,-46.5497 231.341,-36.0554 225.935,-45.1672 232.797,-46.5497\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"169.671\" y=\"-135.285\">1</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g class=\"node\" id=\"node4\"><title>3</title>\n",
"<ellipse cx=\"99\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
"<text 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\"><title>1-&gt;3</title>\n",
"<path d=\"M142.293,-145.116C135.032,-136.04 125.792,-124.49 117.715,-114.393\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"120.252,-111.962 111.272,-106.34 114.786,-116.335 120.252,-111.962\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"138.793\" y=\"-133.916\">2</text>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g class=\"node\" id=\"node6\"><title>5</title>\n",
"<ellipse cx=\"171\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
"<text 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\"><title>1-&gt;5</title>\n",
"<path d=\"M158.873,-144.055C160.655,-136.261 162.812,-126.822 164.811,-118.079\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"168.235,-118.804 167.051,-108.275 161.411,-117.244 168.235,-118.804\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"155.373\" y=\"-132.855\">3</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g class=\"node\" id=\"node5\"><title>4</title>\n",
"<polygon fill=\"none\" points=\"81,-36 27,-36 27,-0 81,-0 81,-36\" stroke=\"black\"/>\n",
"<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"54\" y=\"-14.3\">b</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge2\"><title>3-&gt;4</title>\n",
"<path d=\"M88.7888,-73.1159C83.4437,-64.8013 76.7639,-54.4105 70.6903,-44.9627\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"73.4681,-42.8113 65.1164,-36.2921 67.5799,-46.5966 73.4681,-42.8113\" stroke=\"black\"/>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g class=\"node\" id=\"node7\"><title>6</title>\n",
"<polygon fill=\"none\" points=\"189,-36 135,-36 135,-0 189,-0 189,-36\" stroke=\"black\"/>\n",
"<text 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\"><title>5-&gt;6</title>\n",
"<path d=\"M168.821,-72.055C167.83,-64.3456 166.632,-55.0269 165.518,-46.3642\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"168.968,-45.7473 164.221,-36.2753 162.025,-46.64 168.968,-45.7473\" stroke=\"black\"/>\n",
"</g>\n",
"<!-- 8 -->\n",
"<g class=\"node\" id=\"node9\"><title>8</title>\n",
"<ellipse cx=\"27\" cy=\"-90\" fill=\"none\" rx=\"27\" ry=\"18\" stroke=\"black\"/>\n",
"<text 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\"><title>7-&gt;8</title>\n",
"<path d=\"M50.6534,-144.411C46.9858,-136.129 42.4667,-125.925 38.3646,-116.662\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"41.5434,-115.196 34.2938,-107.47 35.1429,-118.031 41.5434,-115.196\" stroke=\"black\"/>\n",
"</g>\n",
"<!-- 8&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge7\"><title>8-&gt;4</title>\n",
"<path d=\"M33.3986,-72.411C36.4351,-64.5386 40.1417,-54.9289 43.5695,-46.0421\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"46.9373,-47.0364 47.2705,-36.4468 40.4062,-44.5172 46.9373,-47.0364\" stroke=\"black\"/>\n",
"</g>\n",
"</g>\n",
"</svg>"
],
"text": [
"<IPython.core.display.SVG object>"
]
}
],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.formula('F(a & X(!a & b))'); f"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$\\mathsf{F} (a \\land \\mathsf{X} (\\lnot a \\land b))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 18,
"text": [
"F(a & X(!a & b))"
]
}
],
"prompt_number": 18
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Etessami's rule for removing X (valid only in stutter-invariant formulas)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.remove_x(f)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$\\mathsf{F} (a \\land ((a \\land (a \\mathbin{\\mathsf{U}} (\\lnot a \\land b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} \\lnot a) \\lor (b \\mathbin{\\mathsf{U}} \\lnot a))) \\lor (\\lnot a \\land (\\lnot a \\mathbin{\\mathsf{U}} (a \\land \\lnot a \\land b)) \\land ((\\lnot b \\mathbin{\\mathsf{U}} a) \\lor (b \\mathbin{\\mathsf{U}} a))) \\lor (b \\land (b \\mathbin{\\mathsf{U}} (\\lnot a \\land b \\land \\lnot b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} \\lnot b) \\lor (a \\mathbin{\\mathsf{U}} \\lnot b))) \\lor (\\lnot b \\land (\\lnot b \\mathbin{\\mathsf{U}} (\\lnot a \\land b)) \\land ((\\lnot a \\mathbin{\\mathsf{U}} b) \\lor (a \\mathbin{\\mathsf{U}} b))) \\lor (\\lnot a \\land b \\land (\\mathsf{G} \\lnot a \\lor \\mathsf{G} a) \\land (\\mathsf{G} \\lnot b \\lor \\mathsf{G} b))))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 19,
"text": [
"F(a & ((a & (a U (!a & b)) & ((!b U !a) | (b U !a))) | (!a & (!a U (a & !a & b)) & ((!b U a) | (b U a))) | (b & (b U (!a & b & !b)) & ((!a U !b) | (a U !b))) | (!b & (!b U (!a & b)) & ((!a U b) | (a U b))) | (!a & b & (G!a | Ga) & (G!b | Gb))))"
]
}
],
"prompt_number": 19
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Removing abbreviated operators"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.formula(\"G(a xor b) -> F(a <-> b)\")\n",
"spot.unabbreviate(f, \"GF^\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$(\\bot \\mathbin{\\mathsf{R}} \\lnot (a \\leftrightarrow b)) \\rightarrow (\\top \\mathbin{\\mathsf{U}} (a \\leftrightarrow b))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 20,
"text": [
"(0 R !(a <-> b)) -> (1 U (a <-> b))"
]
}
],
"prompt_number": 20
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.unabbreviate(f, \"GF^ei\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"latex": [
"$(\\top \\mathbin{\\mathsf{U}} ((a \\land b) \\lor (\\lnot a \\land \\lnot b))) \\lor \\lnot (\\bot \\mathbin{\\mathsf{R}} ((\\lnot a \\land b) \\lor (a \\land \\lnot b)))$"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 21,
"text": [
"(1 U ((a & b) | (!a & !b))) | !(0 R ((!a & b) | (a & !b)))"
]
}
],
"prompt_number": 21
}
],
"metadata": {}
}
]
}

61
python/tests/implies.py Executable file
View file

@ -0,0 +1,61 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2012 Laboratoire de Recherche et Développement
# de l'EPITA.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from buddy import *
bdd_init(10000, 10000)
bdd_setvarnum(5)
V = [bdd_ithvar(i) for i in range(5)]
a = V[0] & V[1] & -V[2]
b = V[0] & V[1] & -V[2] & -V[3]
c = -V[0] & V[1] & -V[2] & -V[3]
d = V[1] & -V[2]
e = V[1] & V[2] & -V[3] & V[4]
f = V[0] & -V[3] & V[4]
g = -V[0] | V[1]
assert(bdd_implies(b,a))
assert(not bdd_implies(a,b))
assert(not bdd_implies(c,a))
assert(bdd_implies(a,d))
assert(bdd_implies(b,d))
assert(bdd_implies(c,d))
assert(bdd_implies(d,d))
assert(not bdd_implies(e,d))
assert(not bdd_implies(d,e))
assert(not bdd_implies(f,e))
assert(not bdd_implies(e,f))
assert(bdd_implies(bddfalse,f))
assert(not bdd_implies(bddtrue,f))
assert(bdd_implies(f,bddtrue))
assert(not bdd_implies(f,bddfalse))
assert(bdd_implies(a,g))
a = (-V[2] & (-V[1] | V[0])) | (-V[0] & V[1] & V[2])
b = V[1] | -V[2]
assert(bdd_implies(a,b))
# Cleanup all BDD variables before calling bdd_done(), otherwise
# bdd_delref will be called after bdd_done() and this is unsafe in
# optimized builds.
V = a = b = c = d = e = f = g = 0;
bdd_done()

58
python/tests/interdep.py Executable file
View file

@ -0,0 +1,58 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2010, 2012, 2014, 2015 Laboratoire de Recherche et
# Développement de l'EPITA.
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6
# (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
# Pierre et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Make sure that interdependencies between the spot and buddy wrappers
# are not problematic.
import buddy
import spot
import sys
simp = spot.tl_simplifier()
e = spot.default_environment.instance()
p = spot.empty_parse_error_list()
f = spot.parse_infix_psl('GFa', p, e)
d = simp.get_dict()
a = spot.ltl_to_tgba_fm(f, d)
g = spot.parse_infix_boolean('b&c', p, e)
b = simp.as_bdd(g)
buddy.bdd_printset(b); spot.nl_cout()
del g
s0 = a.get_init_state()
it = a.succ_iter(s0)
it.first()
while not it.done():
c = it.cond()
sys.stdout.write("%s\n" % c)
b &= c # `&=' is defined only in buddy. So if this statement works
# it means buddy can grok spot's objects.
buddy.bdd_printset(c); spot.nl_cout()
it.next()
buddy.bdd_printset(b); spot.nl_cout()
sys.stdout.write("%s\n" % b)
del it
del s0
del b
del c
del f
del simp

261
python/tests/ipnbdoctest.py Executable file
View file

@ -0,0 +1,261 @@
#!/usr/bin/env python
"""
simple example script for running and testing notebooks.
Usage: `ipnbdoctest.py foo.ipynb [bar.ipynb [...]]`
Each cell is submitted to the kernel, and the outputs are compared
with those stored in the notebook.
"""
from __future__ import print_function
import os,sys,time
import base64
import re
from difflib import unified_diff as diff
from collections import defaultdict
try:
from queue import Empty
except ImportError:
print('Python 3.x is needed to run this script.')
sys.exit(77)
import imp
try:
imp.find_module('IPython')
except:
print('IPython is needed to run this script.')
sys.exit(77)
try:
from IPython.kernel import KernelManager
except ImportError:
from IPython.zmq.blockingkernelmanager import BlockingKernelManager as KernelManager
# Until Debian ships IPython 3.0, we stick to the v3 format.
from IPython.nbformat import v3 as nbformat
def compare_png(a64, b64):
"""compare two b64 PNGs (incomplete)"""
try:
import Image
except ImportError:
pass
adata = base64.decodestring(a64)
bdata = base64.decodestring(b64)
return True
def sanitize(s):
"""sanitize a string for comparison.
fix universal newlines, strip trailing newlines, and normalize likely
random values (memory addresses and UUIDs)
"""
if not isinstance(s, str):
return s
# normalize newline:
s = s.replace('\r\n', '\n')
# ignore trailing newlines (but not space)
s = s.rstrip('\n')
# remove hex addresses:
s = re.sub(r'at 0x[a-f0-9]+', 'object', s)
# normalize UUIDs:
s = re.sub(r'[a-f0-9]{8}(\-[a-f0-9]{4}){3}\-[a-f0-9]{12}', 'U-U-I-D', s)
# normalize graphviz version
s = re.sub(r'Generated by graphviz version.*', 'VERSION', s)
# ignore %timeit results
s = re.sub(r'^[0-9]+ loops, best of 3:.*per loop', '', s)
# SVG generated by graphviz may put note at different positions
# depending on the graphviz build. Let's just strip anything that
# look like a position.
s = re.sub(r'<path[^/]* d="[^"]*"', '<path', s)
s = re.sub(r'points="[^"]*"', 'points=""', s)
s = re.sub(r'x="[0-9.-]+"', 'x=""', s)
s = re.sub(r'y="[0-9.-]+"', 'y=""', s)
s = re.sub(r'width="[0-9.]+pt"', 'width=""', s)
s = re.sub(r'height="[0-9.]+pt"', 'height=""', s)
s = re.sub(r'viewBox="[0-9 .-]*"', 'viewbox=""', s)
s = re.sub(r'transform="[^"]*"', 'transform=""', s)
return s
def consolidate_outputs(outputs):
"""consolidate outputs into a summary dict (incomplete)"""
data = defaultdict(list)
data['stdout'] = ''
data['stderr'] = ''
for out in outputs:
if out.type == 'stream':
data[out.stream] += out.text
elif out.type == 'pyerr':
data['pyerr'] = dict(ename=out.ename, evalue=out.evalue)
else:
for key in ('png', 'svg', 'latex', 'html',
'javascript', 'text', 'jpeg',):
if key in out:
data[key].append(out[key])
return data
def compare_outputs(test, ref, skip_cmp=('png', 'traceback',
'latex', 'prompt_number')):
for key in ref:
if key not in test:
print("missing key: %s != %s" % (test.keys(), ref.keys()))
return False
elif key not in skip_cmp:
exp = sanitize(ref[key])
eff = sanitize(test[key])
if exp != eff:
print("mismatch %s:" % key)
if exp[:-1] != '\n':
exp += '\n'
if eff[:-1] != '\n':
eff += '\n'
print(''.join(diff(exp.splitlines(1), eff.splitlines(1),
fromfile='expected', tofile='effective')))
return False
return True
def _wait_for_ready_backport(kc):
"""Backport BlockingKernelClient.wait_for_ready from IPython 3"""
# Wait for kernel info reply on shell channel
kc.kernel_info()
while True:
msg = kc.get_shell_msg(block=True, timeout=30)
if msg['msg_type'] == 'kernel_info_reply':
break
# Flush IOPub channel
while True:
try:
msg = kc.get_iopub_msg(block=True, timeout=0.2)
except Empty:
break
def run_cell(kc, cell):
# print cell.input
kc.execute(cell.input)
# wait for finish, maximum 20s
kc.get_shell_msg(timeout=20)
outs = []
while True:
try:
msg = kc.get_iopub_msg(timeout=0.2)
except Empty:
break
msg_type = msg['msg_type']
if msg_type in ('status', 'pyin', 'execute_input'):
continue
elif msg_type == 'clear_output':
outs = []
continue
content = msg['content']
# print (msg_type, content)
if msg_type == 'execute_result':
msg_type = 'pyout'
elif msg_type == 'error':
msg_type = 'pyerr'
out = nbformat.NotebookNode(output_type=msg_type)
if msg_type == 'stream':
out.stream = content['name']
if 'text' in content:
out.text = content['text']
else:
out.text = content['data']
elif msg_type in ('display_data', 'pyout'):
out['metadata'] = content['metadata']
for mime, data in content['data'].items():
attr = mime.split('/')[-1].lower()
# this gets most right, but fix svg+html, plain
attr = attr.replace('+xml', '').replace('plain', 'text')
setattr(out, attr, data)
if 'execution_count' in content:
out.prompt_number = content['execution_count']
elif msg_type == 'pyerr':
out.ename = content['ename']
out.evalue = content['evalue']
out.traceback = content['traceback']
else:
print("unhandled iopub msg:", msg_type)
outs.append(out)
return outs
def test_notebook(nb):
km = KernelManager()
# Do not save the history to disk, as it can yield spurious lock errors.
# See https://github.com/ipython/ipython/issues/2845
km.start_kernel(extra_arguments=['--HistoryManager.hist_file=:memory:'],
stderr=open(os.devnull, 'w'))
kc = km.client()
kc.start_channels()
try:
kc.wait_for_ready()
except AttributeError:
_wait_for_ready_backport(kc)
successes = 0
failures = 0
errors = 0
for ws in nb.worksheets:
for i, cell in enumerate(ws.cells):
if cell.cell_type != 'code':
continue
try:
outs = run_cell(kc, cell)
except Exception as e:
print("failed to run cell:", repr(e))
print(cell.input)
errors += 1
continue
failed = False
if len(outs) != len(cell.outputs):
print("output length mismatch (expected {}, got {})".format(
len(cell.outputs), len(outs)))
failed = True
for out, ref in zip(outs, cell.outputs):
if not compare_outputs(out, ref):
failed = True
print("cell %d: " % i, end="")
if failed:
print("FAIL")
failures += 1
else:
print("OK")
successes += 1
print()
print("tested notebook %s" % nb.metadata.name)
print(" %3i cells successfully replicated" % successes)
if failures:
print(" %3i cells mismatched output" % failures)
if errors:
print(" %3i cells failed to complete" % errors)
kc.stop_channels()
km.shutdown_kernel()
del km
if failures | errors:
sys.exit(1)
if __name__ == '__main__':
for ipynb in sys.argv[1:]:
print("testing %s" % ipynb)
with open(ipynb) as f:
nb = nbformat.reads_json(f.read())
test_notebook(nb)

132
python/tests/ltl2tgba.py Executable file
View file

@ -0,0 +1,132 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2009, 2010, 2012, 2014, 2015 Laboratoire de Recherche et
# Développement de l'Epita (LRDE).
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
# département Systèmes Répartis Coopératifs (SRC), Université Pierre
# et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This is a python implementation of a small ltl2tgba translator that calls the
# translation and simplifications functions itself. It's better to use the
# translate() function today.
import sys
import getopt
import spot
def usage(prog):
sys.stderr.write("""Usage: %s [OPTIONS...] formula
Options:
-d turn on traces during parsing
-D degeneralize the automaton
-f use Couvreur's FM algorithm for translation
-t display reachable states in LBTT's format
-T use ltl2taa for translation
-v display the BDD variables used by the automaton
-W minimize obligation properties
""" % prog)
sys.exit(2)
prog = sys.argv[0]
try:
opts, args = getopt.getopt(sys.argv[1:], 'dDftTvW')
except getopt.GetoptError:
usage(prog)
exit_code = 0
debug_opt = False
degeneralize_opt = None
output = 0
fm_opt = 0
taa_opt = 0
wdba = 0
for o, a in opts:
if o == '-d':
debug_opt = True
elif o == '-D':
degeneralize_opt = 1
elif o == '-f':
fm_opt = 1
elif o == '-t':
output = 6
elif o == '-T':
taa_opt = 1
elif o == '-v':
output = 5
elif o == '-W':
wdba = 1
else:
usage(prog)
if len(args) != 1:
usage(prog)
cout = spot.get_cout()
cerr = spot.get_cerr()
e = spot.default_environment.instance()
p = spot.empty_parse_error_list()
f = spot.parse_infix_psl(args[0], p, e, debug_opt)
if spot.format_parse_errors(cerr, args[0], p):
exit_code = 1
dict = spot.make_bdd_dict()
if f:
if fm_opt:
a = spot.ltl_to_tgba_fm(f, dict)
concrete = 0
elif taa_opt:
a = concrete = spot.ltl_to_taa(f, dict)
else:
assert "unspecified translator"
if wdba:
a = spot.ensure_digraph(a)
a = spot.minimize_obligation(a, f)
del f
degeneralized = None
if degeneralize_opt:
a = degeneralized = spot.degeneralize(a)
if output == 0:
spot.print_dot(cout, a)
elif output == 5:
a.get_dict().dump(cout)
elif output == 6:
spot.print_lbtt(cout, a)
else:
assert "unknown output option"
if degeneralize_opt:
del degeneralized
# Must delete absolutely all references to an automaton
# so that the C++ destructor gets called.
del a, concrete
else:
exit_code = 1
del dict
assert spot.fnode_instances_check()

50
python/tests/ltl2tgba.test Executable file
View file

@ -0,0 +1,50 @@
#!/bin/sh
# Copyright (C) 2014 Laboratoire de Recherche et
# Développement de l'EPITA.
# Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
# département Systèmes Répartis Coopératifs (SRC), Université Pierre
# et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set -e
# We don't check the output, but just running these might be enough to
# trigger assertions.
./run $srcdir/ltl2tgba.py -T a
./run $srcdir/ltl2tgba.py -T 'a U b'
./run $srcdir/ltl2tgba.py -T 'X a'
./run $srcdir/ltl2tgba.py -T 'a & b & c'
./run $srcdir/ltl2tgba.py -T 'a | b | (c U (d & (g U (h ^ i))))'
./run $srcdir/ltl2tgba.py -T 'Xa & (b U !a) & (b U !a)'
./run $srcdir/ltl2tgba.py -T 'Fa & Xb & GFc & Gd'
./run $srcdir/ltl2tgba.py -T 'Fa & Xa & GFc & Gc'
./run $srcdir/ltl2tgba.py -T 'Fc & X(a | Xb) & GF(a | Xb) & Gc'
./run $srcdir/ltl2tgba.py -f a
./run $srcdir/ltl2tgba.py -f 'a U b'
./run $srcdir/ltl2tgba.py -f 'X a'
./run $srcdir/ltl2tgba.py -f 'a & b & c'
./run $srcdir/ltl2tgba.py -f 'a | b | (c U (d & (g U (h ^ i))))'
./run $srcdir/ltl2tgba.py -f 'Xa & (b U !a) & (b U !a)'
./run $srcdir/ltl2tgba.py -f 'Fa & Xb & GFc & Gd'
./run $srcdir/ltl2tgba.py -f 'Fa & Xa & GFc & Gc'
./run $srcdir/ltl2tgba.py -f 'Fc & X(a | Xb) & GF(a | Xb) & Gc'
./run $srcdir/ltl2tgba.py -W -f 'Ga | Gb | Gc'
./run $srcdir/ltl2tgba.py -W -T 'Ga | Gb | Gc'

45
python/tests/ltlparse.py Executable file
View file

@ -0,0 +1,45 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2009, 2010, 2012, 2014, 2015 Laboratoire de Recherche et
# Développement de l'Epita (LRDE).
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
# département Systèmes Répartis Coopératifs (SRC), Université Pierre
# et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import spot
e = spot.default_environment.instance()
p = spot.empty_parse_error_list()
l = ['GFa', 'a U (((b)) xor c)', '!(FFx <=> Fx)', 'a \/ a \/ b \/ a \/ a'];
for str1 in l:
f = spot.parse_infix_psl(str1, p, e, False)
if spot.format_parse_errors(spot.get_cout(), str1, p):
sys.exit(1)
str2 = str(f)
del f
sys.stdout.write(str2 + "\n")
# Try to reparse the stringified formula
f = spot.parse_infix_psl(str2, p, e)
if spot.format_parse_errors(spot.get_cout(), str2, p):
sys.exit(1)
sys.stdout.write(str(f) + "\n")
del f
assert spot.fnode_instances_check()

118
python/tests/ltlsimple.py Executable file
View file

@ -0,0 +1,118 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2009, 2010, 2012, 2015 Laboratoire de Recherche et Développement
# de l'Epita (LRDE).
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
# département Systemes Répartis Coopératifs (SRC), Université Pierre
# et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
import sys
#----------------------------------------------------------------------
a = spot.formula.ap('a')
b = spot.formula.ap('b')
c = spot.formula.ap('c')
c2 = spot.formula.ap('c')
assert c == c2
op = spot.formula.And([a, b])
op2 = spot.formula.And([op, c])
op3 = spot.formula.And([a, c, b])
assert op2 == op3
# The symbol for a subformula which hasn't been cloned is better
# suppressed, so we don't attempt to reuse it elsewhere.
del op, c
sys.stdout.write('op2 = %s\n' % str(op2))
del a, b, c2
sys.stdout.write('op3 = %s\n' % str(op3))
assert op2 == op3
op4 = spot.formula.Or([op2, op3])
sys.stdout.write('op4 = %s\n' % str(op4))
assert op4 == op2
del op2, op3, op4
#----------------------------------------------------------------------
a = spot.formula.ap('a')
b = spot.formula.ap('b')
c = spot.formula.ap('c')
T = spot.formula.tt()
F = spot.formula.ff()
f1 = spot.formula.Equiv(c, a)
f2 = spot.formula.Implies(a, b)
f3 = spot.formula.Xor(b, c)
f4 = spot.formula.Not(f3); del f3
f5 = spot.formula.Xor(F, c)
del a, b, c, T, F, f1, f2, f4, f5
assert spot.fnode_instances_check()
#----------------------------------------------------------------------
assert str([x for x in spot.formula('a &b & c')]) == '[a, b, c]'
def switch_g_f(x):
if x._is(spot.op_G):
return spot.formula.F(switch_g_f(x[0]))
if x._is(spot.op_F):
return spot.formula.G(switch_g_f(x[0]))
return x.map(switch_g_f)
f = spot.formula('GFa & XFGb & Fc & G(a | b | Fd)')
assert str(switch_g_f(f)) == 'FGa & XGFb & Gc & F(a | b | Gd)'
x = 0
def count_g(f):
global x
if f._is(spot.op_G):
x += 1
f.traverse(count_g)
assert x == 3
#----------------------------------------------------------------------
# The example from tut01.org
formula = spot.formula('a U b U "$strange[0]=name"')
res = """\
Default output: {f}
Spin syntax: {f:s}
(Spin syntax): {f:sp}
Default for shell: echo {f:q} | ...
LBT for shell: echo {f:lq} | ...
Default for CSV: ...,{f:c},...
Wring, centered: {f:w:~^50}""".format(f = formula)
assert res == """\
Default output: a U (b U "$strange[0]=name")
Spin syntax: a U (b U ($strange[0]=name))
(Spin syntax): (a) U ((b) U ($strange[0]=name))
Default for shell: echo 'a U (b U "$strange[0]=name")' | ...
LBT for shell: echo 'U "a" U "b" "$strange[0]=name"' | ...
Default for CSV: ...,"a U (b U ""$strange[0]=name"")",...
Wring, centered: ~~~~~(a=1) U ((b=1) U ("$strange[0]=name"=1))~~~~~"""

47
python/tests/minato.py Executable file
View file

@ -0,0 +1,47 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2010, 2012, 2013, 2014 Laboratoire de Recherche et
# Développement de l'Epita
# Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
# département Systèmes Répartis Coopératifs (SRC), Université Pierre
# et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import buddy
import sys
buddy.bdd_init(10000, 10000)
buddy.bdd_setvarnum(3)
a = buddy.bdd_ithvar(0)
b = buddy.bdd_ithvar(1)
c = buddy.bdd_ithvar(2)
w = -a & -b | -c & b | a & -b
import spot
isop = spot.minato_isop(w)
i = isop.next()
l = []
while i != buddy.bddfalse:
buddy.bdd_printset(i)
spot.nl_cout()
l.append(i)
i = isop.next()
sys.exit(l == [-a, -c])

59
python/tests/optionmap.py Executable file
View file

@ -0,0 +1,59 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2010, 2012 Laboratoire de Recherche et Développement
# de l'EPITA.
# Copyright (C) 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
# département Systèmes Répartis Coopératifs (SRC), Université Pierre
# et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
o = spot.option_map()
res = o.parse_options("optA, opta=2M, optb =4 ; optB = 7\
, optC= 10")
assert not res
assert o.get('optA') == 1
assert o.get('opta') == 2*1024*1024
assert o.get('optb') == 4
assert o.get('optB') == 7
assert o.get('optC') == 10
assert o.get('none') == 0
assert o.get('none', 16) == 16
o.set('optb', 40)
assert o.get('optb') == 40
res = o.parse_options("!optA !optb optC, !optB")
assert not res
assert o.get('optA') == 0
assert o.get('opta') == 2*1024*1024
assert o.get('optb') == 0
assert o.get('optB') == 0
assert o.get('optC') == 1
res = o.parse_options("!")
assert res == "!"
res = o.parse_options("foo, !opt = 1")
assert res == "!opt = 1"
res = o.parse_options("foo=3, opt == 1")
assert res == "opt == 1"
res = o.parse_options("foo=3opt == 1")
assert res == "3opt == 1"

43
python/tests/parsetgba.py Executable file
View file

@ -0,0 +1,43 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2012, 2014, 2015 Laboratoire de Recherche et Développement
# de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import spot
contents = '''
HOA: v1 name: "a U b" States: 2 Start: 1 AP: 2 "a" "b" acc-name: Buchi
Acceptance: 1 Inf(0) properties: trans-labels explicit-labels state-acc
deterministic --BODY-- State: 0 {0} [t] 0 State: 1 [1] 0 [0&!1] 1 --END--
'''
filename = 'parsetgba.hoa'
out = open(filename, 'w+')
out.write(contents)
out.close()
a = spot.parse_aut(filename, spot.make_bdd_dict())
assert not a.errors
spot.print_dot(spot.get_cout(), a.aut)
del a
os.unlink(filename)

499
python/tests/piperead.ipynb Normal file
View file

@ -0,0 +1,499 @@
{
"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.4.3+"
},
"name": "",
"signature": "sha256:471d70bbd30f4ffde7ebceb35a8f4a1ca66baba3ad959b99d4bb72ef81e4d5cf"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.display import display \n",
"import spot\n",
"spot.setup()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Reading automata output from processes\n",
"\n",
"If an argument of `spot.automata` ends with `|`, then it is interpreted as a shell command that outputs one automaton or more."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for a in spot.automata('ltl2tgba -s \"a U b\"; ltl2tgba --lbtt \"b\"|', 'ltl2tgba -H \"GFa\" \"a & GFb\"|'):\n",
" display(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f1084090540> >"
]
},
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f1084090600> >"
]
},
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"82pt\" height=\"125pt\"\n",
" viewBox=\"0.00 0.00 82.00 125.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 121)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-121 78,-121 78,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" 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\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-18C2.79388,-18 17.1543,-18 30.6317,-18\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-18 30.9419,-21.1501 34.4419,-18 30.9419,-18.0001 30.9419,-18.0001 30.9419,-18.0001 34.4419,-18 30.9418,-14.8501 37.9419,-18 37.9419,-18\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M52.7643,-35.7817C52.2144,-45.3149 53.293,-54 56,-54 57.988,-54 59.0977,-49.3161 59.3292,-43.0521\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"59.2357,-35.7817 62.4756,-42.7406 59.2808,-39.2814 59.3258,-42.7812 59.3258,-42.7812 59.3258,-42.7812 59.2808,-39.2814 56.1761,-42.8217 59.2357,-35.7817 59.2357,-35.7817\"/>\n",
"<text text-anchor=\"start\" x=\"52.5\" y=\"-72.8\" font-family=\"Lato\" font-size=\"14.00\">a</text>\n",
"<text text-anchor=\"start\" x=\"48\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#5da5da\">\u24ff</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M50.9906,-35.5771C47.5451,-56.718 49.2148,-84 56,-84 62.043,-84 64.0285,-62.3596 61.9564,-42.6907\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"61.0094,-35.5771 65.0556,-42.1002 61.4713,-39.0465 61.9332,-42.5159 61.9332,-42.5159 61.9332,-42.5159 61.4713,-39.0465 58.8107,-42.9316 61.0094,-35.5771 61.0094,-35.5771\"/>\n",
"<text text-anchor=\"start\" x=\"50.5\" y=\"-87.8\" font-family=\"Lato\" font-size=\"14.00\">!a</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f1084090540> >"
]
},
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"161pt\" height=\"125pt\"\n",
" viewBox=\"0.00 0.00 161.00 125.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 121)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-121 157,-121 157,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" 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\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-18C2.79388,-18 17.1543,-18 30.6317,-18\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-18 30.9419,-21.1501 34.4419,-18 30.9419,-18.0001 30.9419,-18.0001 30.9419,-18.0001 34.4419,-18 30.9418,-14.8501 37.9419,-18 37.9419,-18\"/>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"135\" cy=\"-18\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"135\" y=\"-14.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.0888,-18C84.5562,-18 98.1196,-18 109.693,-18\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"116.959,-18 109.959,-21.1501 113.459,-18 109.959,-18.0001 109.959,-18.0001 109.959,-18.0001 113.459,-18 109.959,-14.8501 116.959,-18 116.959,-18\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-21.8\" font-family=\"Lato\" font-size=\"14.00\">a</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M131.584,-35.7817C131.004,-45.3149 132.143,-54 135,-54 137.098,-54 138.27,-49.3161 138.514,-43.0521\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"138.416,-35.7817 141.66,-42.7383 138.463,-39.2814 138.511,-42.7811 138.511,-42.7811 138.511,-42.7811 138.463,-39.2814 135.361,-42.8239 138.416,-35.7817 138.416,-35.7817\"/>\n",
"<text text-anchor=\"start\" x=\"130.5\" y=\"-72.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"<text text-anchor=\"start\" x=\"127\" y=\"-57.8\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#5da5da\">\u24ff</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M129.769,-35.249C126.057,-56.4346 127.801,-84 135,-84 141.412,-84 143.496,-62.1347 141.253,-42.3851\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"140.231,-35.249 144.342,-41.7316 140.727,-38.7137 141.223,-42.1783 141.223,-42.1783 141.223,-42.1783 140.727,-38.7137 138.105,-42.625 140.231,-35.249 140.231,-35.249\"/>\n",
"<text text-anchor=\"start\" x=\"128.5\" y=\"-87.8\" font-family=\"Lato\" font-size=\"14.00\">!b</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f1084090600> >"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A single automaton can be read using `spot.automaton()`, with the same convention."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.automaton('ltl2tgba -s6 \"a U b\"|')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 0 -->\n",
"<g id=\"node2\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f10840a0570> >"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Error handling\n",
"\n",
"If the shell command terminates with a non-zero exit status, we should get an exception."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.automaton('non-existing-command|')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "CalledProcessError",
"evalue": "Command 'non-existing-command' returned non-zero exit status 127",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-4-765c7cc6937f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'non-existing-command|'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 404\u001b[0m See `spot.automata` for a list of supported formats.\"\"\"\n\u001b[1;32m 405\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 406\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 407\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 408\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, *sources)\u001b[0m\n\u001b[1;32m 395\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 396\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 397\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 398\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mCalledProcessError\u001b[0m: Command 'non-existing-command' returned non-zero exit status 127"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for a in spot.automata(\"ltl2tgba -H 'a U b'|\", 'ltl2tgba -f \"syntax U U error\"|'):\n",
" display(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"37.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f10840a00c0> >"
]
},
{
"ename": "CalledProcessError",
"evalue": "Command 'ltl2tgba -f \"syntax U U error\"' returned non-zero exit status 2",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-5-21a24ff75c32>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0ma\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"ltl2tgba -H 'a U b'|\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'ltl2tgba -f \"syntax U U error\"|'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomata\u001b[0;34m(timeout, *sources)\u001b[0m\n\u001b[1;32m 395\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mproc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 396\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mret\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 397\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0msubprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCalledProcessError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mret\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilename\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 398\u001b[0m \u001b[0;32mreturn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mCalledProcessError\u001b[0m: Command 'ltl2tgba -f \"syntax U U error\"' returned non-zero exit status 2"
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Reading an empty file with `spot.automaton()` is an error."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.automaton('true|')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "RuntimeError",
"evalue": "Failed to read automaton from true|",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-6-f4e056a50029>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mspot\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautomaton\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'true|'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/home/adl/git/spot/wrap/python/spot.py\u001b[0m in \u001b[0;36mautomaton\u001b[0;34m(filename, **kwargs)\u001b[0m\n\u001b[1;32m 406\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mautomata\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 407\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 408\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Failed to read automaton from {}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 409\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 410\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mRuntimeError\u001b[0m: Failed to read automaton from true|"
]
}
],
"prompt_number": 6
}
],
"metadata": {}
}
]
}

2001
python/tests/product.ipynb Normal file

File diff suppressed because it is too large Load diff

2285
python/tests/randaut.ipynb Normal file

File diff suppressed because it is too large Load diff

26
python/tests/randgen.py Executable file
View file

@ -0,0 +1,26 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2015 Laboratoire de Recherche et Développement de
# l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
o = spot.option_map()
g = spot.randltlgenerator(0, o)
assert str(g.next()) == '1'
assert str(g.next()) == '0'
assert str(g.next()) == 'None'

677
python/tests/randltl.ipynb Normal file
View file

@ -0,0 +1,677 @@
{
"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.4.3+"
},
"name": "",
"signature": "sha256:c1de5aacd024bbec64b75f61a13e53562185c906051312d9ce5067236b7899d4"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Documentation for spot's randltl python binding"
]
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"import spot"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Basic usage"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generate random formulas from specified atomic propositions:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(['a', 'b', 'c'])\n",
"for i in range(3):\n",
" print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"0 R b\n",
"F(XG(F!b M Fb) W (b R a))\n"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generate random formulas using 3 atomic propositions:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3)\n",
"for i in range(3):\n",
" print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"0 R p1\n",
"F(XG(F!p1 M Fp1) W (p1 R p0))\n"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default, there is no limit to the number of formulas generated.<br/>\n",
"To specify a number of formulas:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, 4)\n",
"for formula in f:\n",
" print(formula)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"0 R p1\n",
"F(XG(F!p1 M Fp1) W (p1 R p0))\n",
"F(p0 R !p2)\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Keyword arguments"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"seed"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Seed for the pseudo random number generator (default: 0)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, seed=11)\n",
"print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"G(p1 U Gp0)\n"
]
}
],
"prompt_number": 5
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Type of formulas to output: 'ltl', 'psl', 'bool' or 'sere' (default: 'ltl')."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, output='psl', seed=332)\n",
"print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{{p0 && p2}[*]}<>-> (Fp2 & Fp0)\n"
]
}
],
"prompt_number": 6
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"allow_dups"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Allow duplicate formulas (default: False)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(1, allow_dups=True)\n",
"print(next(f))\n",
"print(next(f))\n",
"print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"0\n",
"Fp0\n"
]
}
],
"prompt_number": 7
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"tree_size"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Tree size of the formulas generated, before mandatory simplifications (default: 15)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, tree_size=30, seed=11)\n",
"print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"G(((p0 U !Xp1) M Gp1) U Gp0)\n"
]
}
],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A range can be specified as a tuple:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, tree_size=(1, 40))\n",
"print(next(f))\n",
"print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"X!(Gp1 M p2) R (!p2 M Xp1)\n",
"F(G(F(Gp0 R (1 U Fp2)) M (p2 -> Gp0)) M F((p0 | Fp0) W Gp2))\n"
]
}
],
"prompt_number": 9
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"boolean_priorities, ltl_priorities, sere_priorities, dump_priorities"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, output='bool', boolean_priorities='and=10,or=0')\n",
"for i in range(5):\n",
" print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"!p2 & (p1 <-> p2)\n",
"p2\n",
"p0 & ((p1 & p2) <-> !(!p0 & p1 & p2))\n",
"1\n"
]
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To see which operators are available along with their default priorities:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.randltl(3, output='psl', dump_priorities=True)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Use argument ltl_priorities=STRING to set the following LTL priorities:\n",
"\n",
"ap\t3\n",
"false\t1\n",
"true\t1\n",
"not\t1\n",
"F\t1\n",
"G\t1\n",
"X\t1\n",
"Closure\t1\n",
"equiv\t1\n",
"implies\t1\n",
"xor\t1\n",
"R\t1\n",
"U\t1\n",
"W\t1\n",
"M\t1\n",
"and\t1\n",
"or\t1\n",
"EConcat\t1\n",
"UConcat\t1\n",
"\n",
"Use argument sere_priorities=STRING to set the following SERE priorities:\n",
"\n",
"ap\t3\n",
"false\t1\n",
"true\t1\n",
"not\t1\n",
"F\t1\n",
"G\t1\n",
"X\t1\n",
"Closure\t1\n",
"equiv\t1\n",
"implies\t1\n",
"xor\t1\n",
"R\t1\n",
"U\t1\n",
"W\t1\n",
"M\t1\n",
"and\t1\n",
"or\t1\n",
"EConcat\t1\n",
"UConcat\t1\n",
"eword\t1\n",
"boolform\t1\n",
"star\t1\n",
"star_b\t1\n",
"fstar\t1\n",
"fstar_b\t1\n",
"and\t1\n",
"andNLM\t1\n",
"or\t1\n",
"concat\t1\n",
"fusion\t1\n",
"\n",
"Use argument boolean_priorities=STRING to set the following Boolean formula priorities:\n",
"\n",
"ap\t3\n",
"false\t1\n",
"true\t1\n",
"not\t1\n",
"F\t1\n",
"G\t1\n",
"X\t1\n",
"Closure\t1\n",
"equiv\t1\n",
"implies\t1\n",
"xor\t1\n",
"R\t1\n",
"U\t1\n",
"W\t1\n",
"M\t1\n",
"and\t1\n",
"or\t1\n",
"EConcat\t1\n",
"UConcat\t1\n",
"eword\t1\n",
"boolform\t1\n",
"star\t1\n",
"star_b\t1\n",
"fstar\t1\n",
"fstar_b\t1\n",
"and\t1\n",
"andNLM\t1\n",
"or\t1\n",
"concat\t1\n",
"fusion\t1\n",
"ap\t3\n",
"false\t1\n",
"true\t1\n",
"not\t1\n",
"equiv\t1\n",
"implies\t1\n",
"xor\t1\n",
"and\t1\n",
"or\t1\n",
"\n"
]
}
],
"prompt_number": 11
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"simplify"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"0 No rewriting<br/>\n",
"1 basic rewritings and eventual/universal rules<br/>\n",
"2 additional syntactic implication rules<br/>\n",
"3 better implications using containment<br/>\n",
"default: 3"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, simplify=0, seed=5)\n",
"print(next(f))\n",
"f = spot.randltl(3, simplify=3, seed=5)\n",
"print(next(f))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"G!(!p1 & (Xp2 | F(p0 R Xp2)))\n",
"G(p1 | (X!p2 & G(!p0 U X!p2)))\n"
]
}
],
"prompt_number": 12
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Filters and maps"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"most boolean functions found in the class formula can be used to filter the random formula generator like this:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, 20).is_syntactic_stutter_invariant()\n",
"for formula in f:\n",
" print(formula)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"0 R p2\n",
"F(p0 R !p1)\n",
"G(p0 | Fp2) W (FGp2 R !p2)\n",
"(p2 R G!p1) | G(p2 U !p0)\n",
"(p2 W p0) U p2\n",
"F!G(!Gp1 W p1)\n",
"G!p1 & (!((p2 & Fp1) M p1) U p1)\n"
]
}
],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"likewise, functions from formula to formula can be applied to map the iterator:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(2, 6).remove_x()\n",
"for formula in f:\n",
" print(formula)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"!(F!p1 M 1)\n",
"(Gp0 | Fp1) M 1\n",
"F!(!p1 <-> FGp1)\n",
"Gp1 U (p1 U GFp1)\n",
"(!p1 U p1) U ((p0 & (p0 U (!p0 & (!p0 -> Fp1))) & ((!p1 U !p0) | (p1 U !p0))) | (!p0 & (!p0 U (p0 & (!p0 -> Fp1))) & ((!p1 U p0) | (p1 U p0))) | (p1 & (p1 U (!p1 & (!p0 -> Fp1))) & ((!p0 U !p1) | (p0 U !p1))) | (!p1 & (!p1 U (p1 & (!p0 -> Fp1))) & ((!p0 U p1) | (p0 U p1))) | ((!p0 -> Fp1) & (Gp0 | G!p0) & (Gp1 | G!p1)))\n"
]
}
],
"prompt_number": 14
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since the boolean filters and mapping functions return an iterator of the same type, these operations can be chained like this:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.randltl(3, 20).is_syntactic_stutter_invariant().relabel(spot.Abc).simplify()\n",
"for formula in f:\n",
" print(formula)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"Ga\n",
"F(a R !b)\n",
"G(a | Fb) | (FGb R !b)\n",
"G!b | G(a U !c)\n",
"b U a\n",
"0\n",
"0\n"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for formula in spot.randltl(3, 10).simplify().unabbreviate(\"WMGFR\"): print(formula)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"!(1 U !p1)\n",
"1 U ((p0 U ((p0 & p1) | !(1 U !p0))) | !(1 U !((1 U !p1) & (1 U p1))))\n",
"1 U (!p2 U ((p0 & !p2) | !(1 U p2)))\n",
"(!p1 U ((!p1 & (1 U !(1 U !p1))) | !(1 U p1))) | !(1 U !(p0 | (1 U p1)))\n",
"X(p2 & X(p2 U (!p0 | !(1 U !p2))))\n",
"(1 U p2) | (X(!p2 | !(1 U !p2)) U ((1 U p2) U (!p1 & (1 U p2))))\n",
"XX!(1 U !((X!p1 U (!p2 U (!p0 & !p2))) | X!(1 U !p0)))\n",
"XX(1 U (p1 U ((p0 & p1) | !(1 U !p1))))\n",
"p2 & Xp0\n"
]
}
],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 16
}
],
"metadata": {}
}
]
}

32
python/tests/relabel.py Normal file
View file

@ -0,0 +1,32 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2015 Laboratoire de Recherche et Développement
# de l'Epita
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import spot
f = spot.formula('GF(a & b) -> (FG(a & b) & Gc)')
m = spot.relabeling_map()
g = spot.relabel_bse(f, spot.Pnn, m)
res = ""
for old, new in m.items():
res += "#define {} {}\n".format(old, new)
res += str(g)
print(res)
assert(res == """#define p0 a & b
#define p1 c
GFp0 -> (FGp0 & Gp1)""")

49
python/tests/remfin.py Normal file
View file

@ -0,0 +1,49 @@
import spot
# This test used to trigger an assertion (or a segfault)
# in scc_filter_states().
aut = spot.automaton("""
HOA: v1
States: 3
Start: 1
AP: 1 "a"
Acceptance: 1 Inf(0)
--BODY--
State: 0 {0}
[t] 0
State: 1
[!0] 0
[0] 2
State: 2
[t] 2
--END--
""")
aut.prop_inherently_weak(True)
aut = spot.dtwa_complement(aut)
aut1 = spot.scc_filter_states(aut)
assert(aut1.to_str('hoa') == """HOA: v1
States: 2
Start: 0
AP: 1 "a"
acc-name: co-Buchi
Acceptance: 1 Fin(0)
properties: trans-labels explicit-labels state-acc deterministic
properties: inherently-weak
--BODY--
State: 0
[0] 1
State: 1
[t] 1
--END--""")
assert(aut.scc_filter_states().to_str() == aut1.to_str())
assert(aut1.get_name() == None)
aut1.set_name("test me")
assert(aut1.get_name() == "test me")
# The method is the same as the function
a = spot.translate('true', 'low', 'any')
assert(a.prop_deterministic() == False)
assert(a.prop_unambiguous() == False)
assert(a.is_deterministic() == True)
assert(a.is_unambiguous() == True)

56
python/tests/run.in Executable file
View file

@ -0,0 +1,56 @@
#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2010, 2011, 2014, 2015 Laboratoire de Recherche et
# Developpement de l'EPITA (LRDE).
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6
# (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
# Pierre et Marie Curie.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Darwin needs some help in figuring out where non-installed libtool
# libraries are (on this platform libtool encodes the expected final
# path of dependent libraries in each library).
modpath='../.libs:@top_builddir@/spot/.libs:@top_builddir@/buddy/spot/.libs'
# .. is for the *.py files, and ../.libs for the *.so. We used to
# rely on a module called ltihooks.py to teach the import function how
# to load a Libtool library, but it started to cause issues with
# Python 2.6.
pypath='..:../.libs:@srcdir@/..:@srcdir@/../.libs:$PYTHONPATH'
PATH="@abs_top_builddir@/spot/bin:$PATH"
export PATH
test -z "$1" &&
PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath exec @PYTHON@
case $1 in
*.ipynb)
PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath \
exec $PREFIXCMD @PYTHON@ @srcdir@/ipnbdoctest.py "$@";;
*.py)
PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath \
exec $PREFIXCMD @PYTHON@ "$@";;
*.test)
exec sh -x "$@";;
*python*)
PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath \
exec $PREFIXCMD "$@";;
*)
echo "Unknown extension" >&2
exit 2;;
esac

49
python/tests/satmin.py Normal file
View file

@ -0,0 +1,49 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2015 Laboratoire de Recherche et Développement
# de l'Epita
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import shutil
import sys
import spot
# Ignore the test if glucose is not installed.
if shutil.which("glucose") == None:
sys.exit(77)
aut = spot.translate('GFa & GFb', 'BA')
assert aut.num_sets() == 1
assert aut.num_states() == 3
assert aut.is_deterministic()
min1 = spot.sat_minimize(aut, acc='Rabin 1')
assert min1.num_sets() == 2
assert min1.num_states() == 2
min2 = spot.sat_minimize(aut, acc='Streett 2', dichotomy=True)
assert min2.num_sets() == 4
assert min2.num_states() == 1
min3 = spot.sat_minimize(aut, acc='Rabin 2',
state_based=True, max_states=5, dichotomy=True)
assert min3.num_sets() == 4
assert min3.num_states() == 3
min4 = spot.sat_minimize(aut, acc='parity max odd 3',
colored=True, dichotomy=True)
assert min4.num_sets() == 3
assert min4.num_states() == 2

49
python/tests/setxor.py Executable file
View file

@ -0,0 +1,49 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2010, 2011 Laboratoire de Recherche et Développement
# de l'EPITA.
#
# This file is part of Spot, a model checking library.
#
# Spot is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Spot is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
from buddy import *
bdd_init(10000, 10000)
bdd_setvarnum(5)
V = [bdd_ithvar(i) for i in range(5)]
a = V[0] & -V[1] & V[2] & -V[3]
b = V[0] & V[1] & V[2] & -V[3]
c = -V[0] & V[1] & -V[2] & -V[3]
assert(c == bdd_setxor(a,b))
assert(c == bdd_setxor(b,a))
assert(a == bdd_setxor(b,c))
assert(a == bdd_setxor(c,b))
assert(b == bdd_setxor(a,c))
assert(b == bdd_setxor(c,a))
d = V[1] & V[2] & -V[3] & V[4]
e = V[0] & V[1] & -V[2] & -V[3] & V[4]
assert(e == bdd_setxor(a,d))
assert(e == bdd_setxor(d,a))
# Cleanup all BDD variables before calling bdd_done(), otherwise
# bdd_delref will be called after bdd_done() and this is unsafe in
# optimized builds.
V = a = b = c = d = e = 0;
bdd_done()

View file

@ -0,0 +1,651 @@
{
"metadata": {
"name": "",
"signature": "sha256:1a85b698ebae51aaba0387d782d1cf5c6cdf54f69dd6b4b9c7189f8676eb4c88"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.display import display, HTML\n",
"import spot\n",
"spot.setup()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To translate a formula into a Testing Automaton\n",
"\n",
"Start by building a Buchi automaton"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = spot.formula('a U Gb')\n",
"a = f.translate('ba')\n",
"a"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 2,
"svg": [
"<?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.38.0 (20140413.2041)\n",
" -->\n",
"<!-- Title: G Pages: 1 -->\n",
"<svg width=\"171pt\" height=\"85pt\"\n",
" viewBox=\"0.00 0.00 171.00 85.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 81)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-81 167,-81 167,4 -4,4\"/>\n",
"<!-- I -->\n",
"<!-- 1 -->\n",
"<g id=\"node2\" class=\"node\"><title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"56\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<text text-anchor=\"middle\" x=\"56\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">1</text>\n",
"</g>\n",
"<!-- I&#45;&gt;1 -->\n",
"<g id=\"edge1\" class=\"edge\"><title>I&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M1.15491,-22C2.79388,-22 17.1543,-22 30.6317,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"37.9419,-22 30.9419,-25.1501 34.4419,-22 30.9419,-22.0001 30.9419,-22.0001 30.9419,-22.0001 34.4419,-22 30.9418,-18.8501 37.9419,-22 37.9419,-22\"/>\n",
"</g>\n",
"<!-- 1&#45;&gt;1 -->\n",
"<g id=\"edge4\" class=\"edge\"><title>1&#45;&gt;1</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M49.6208,-39.0373C48.3189,-48.8579 50.4453,-58 56,-58 60.166,-58 62.4036,-52.8576 62.7128,-46.1433\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"62.3792,-39.0373 65.8541,-45.8818 62.5434,-42.5335 62.7076,-46.0296 62.7076,-46.0296 62.7076,-46.0296 62.5434,-42.5335 59.561,-46.1774 62.3792,-39.0373 62.3792,-39.0373\"/>\n",
"<text text-anchor=\"start\" x=\"52.5\" y=\"-61.8\" font-family=\"Lato\" font-size=\"14.00\">a</text>\n",
"</g>\n",
"<!-- 0 -->\n",
"<g id=\"node3\" class=\"node\"><title>0</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"18\" ry=\"18\"/>\n",
"<ellipse fill=\"none\" stroke=\"black\" cx=\"141\" cy=\"-22\" rx=\"22\" ry=\"22\"/>\n",
"<text text-anchor=\"middle\" x=\"141\" y=\"-18.3\" font-family=\"Lato\" font-size=\"14.00\">0</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;0 -->\n",
"<g id=\"edge3\" class=\"edge\"><title>1&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M74.1977,-22C85.0734,-22 99.3874,-22 111.887,-22\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"118.997,-22 111.997,-25.1501 115.497,-22 111.997,-22.0001 111.997,-22.0001 111.997,-22.0001 115.497,-22 111.997,-18.8501 118.997,-22 118.997,-22\"/>\n",
"<text text-anchor=\"start\" x=\"92\" y=\"-25.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;0 -->\n",
"<g id=\"edge2\" class=\"edge\"><title>0&#45;&gt;0</title>\n",
"<path fill=\"none\" stroke=\"black\" d=\"M132.994,-42.5808C131.886,-52.8447 134.555,-62 141,-62 145.834,-62 148.544,-56.8502 149.129,-49.9451\"/>\n",
"<polygon fill=\"black\" stroke=\"black\" points=\"149.006,-42.5808 152.273,-49.5273 149.065,-46.0803 149.123,-49.5798 149.123,-49.5798 149.123,-49.5798 149.065,-46.0803 145.973,-49.6324 149.006,-42.5808 149.006,-42.5808\"/>\n",
"<text text-anchor=\"start\" x=\"136.5\" y=\"-65.8\" font-family=\"Lato\" font-size=\"14.00\">b</text>\n",
"</g>\n",
"</g>\n",
"</svg>\n"
],
"text": [
"<spot_impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f2e817bf6c0> >"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, gather all the atomic proposition in the formula, and create an automaton with changesets"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"propset = spot.atomic_prop_collect_as_bdd(f, a)\n",
"ta = spot.tgba_to_ta(a, propset, True, True, False, False, True)\n",
"ta.show('.A')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"svg": [
"<svg height=\"295pt\" viewBox=\"0.00 0.00 734.00 295.42\" width=\"734pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g class=\"graph\" id=\"graph0\" transform=\"scale(0.749788 0.749788) rotate(0) translate(4 390)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" points=\"-4,4 -4,-390 974.944,-390 974.944,4 -4,4\" stroke=\"none\"/>\n",
"<!-- 0 -->\n",
"<!-- 1 -->\n",
"<g class=\"node\" id=\"node2\"><title>1</title>\n",
"<ellipse cx=\"62.6978\" cy=\"-256\" fill=\"#ffffaa\" rx=\"24.8972\" ry=\"24.8972\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"62.6978\" y=\"-252.3\">init</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g class=\"edge\" id=\"edge1\"><title>0-&gt;1</title>\n",
"<path d=\"M1.04399,-256C1.93865,-256 16.3331,-256 30.8732,-256\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"37.9642,-256 30.9643,-259.15 34.4642,-256 30.9642,-256 30.9642,-256 30.9642,-256 34.4642,-256 30.9642,-252.85 37.9642,-256 37.9642,-256\" stroke=\"black\"/>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g class=\"node\" id=\"node3\"><title>2</title>\n",
"<ellipse cx=\"482.365\" cy=\"-190\" fill=\"#ffffaa\" rx=\"37.4533\" ry=\"37.4533\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"482.365\" y=\"-193.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"482.365\" y=\"-178.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge2\"><title>1-&gt;2</title>\n",
"<path d=\"M80.0021,-274.105C115.083,-310.768 201.199,-388.632 283.106,-368 356.606,-349.486 378.744,-332.757 424.06,-272 434.518,-257.978 432.39,-251.576 442.06,-237 445.119,-232.388 448.559,-227.709 452.097,-223.181\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"456.612,-217.543 454.696,-224.976 454.424,-220.275 452.237,-223.008 452.237,-223.008 452.237,-223.008 454.424,-220.275 449.778,-221.039 456.612,-217.543 456.612,-217.543\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"264.606\" y=\"-374.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g class=\"node\" id=\"node4\"><title>3</title>\n",
"<ellipse cx=\"192.751\" cy=\"-152\" fill=\"#ffffaa\" rx=\"35.2113\" ry=\"35.2113\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"192.751\" y=\"-155.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"192.751\" y=\"-140.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge3\"><title>1-&gt;3</title>\n",
"<path d=\"M82.3178,-240.878C102.354,-224.605 134.612,-198.406 158.925,-178.66\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"164.609,-174.044 161.161,-180.902 161.892,-176.25 159.175,-178.457 159.175,-178.457 159.175,-178.457 161.892,-176.25 157.189,-176.012 164.609,-174.044 164.609,-174.044\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"122.396\" y=\"-223.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g class=\"node\" id=\"node5\"><title>4</title>\n",
"<ellipse cx=\"338.583\" cy=\"-205\" fill=\"#ffffaa\" rx=\"37.4533\" ry=\"37.4533\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"338.583\" y=\"-208.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"338.583\" y=\"-193.8\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge4\"><title>1-&gt;4</title>\n",
"<path d=\"M87.1814,-252.544C119.148,-247.749 178.107,-238.579 228.106,-229 250.158,-224.775 274.574,-219.483 294.742,-214.943\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"301.687,-213.372 295.555,-217.989 298.274,-214.145 294.86,-214.917 294.86,-214.917 294.86,-214.917 298.274,-214.145 294.165,-211.844 301.687,-213.372 301.687,-213.372\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"192.751\" y=\"-245.8\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g class=\"node\" id=\"node6\"><title>5</title>\n",
"<ellipse cx=\"628.025\" cy=\"-158\" fill=\"#ffffaa\" rx=\"35.2259\" ry=\"35.2259\" stroke=\"black\"/>\n",
"<ellipse cx=\"628.025\" cy=\"-158\" fill=\"none\" rx=\"39.2112\" ry=\"39.2112\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"628.025\" y=\"-161.8\">0</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"628.025\" y=\"-146.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge5\"><title>2-&gt;5</title>\n",
"<path d=\"M519.246,-182.008C538.352,-177.752 562.03,-172.478 582.322,-167.958\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"589.345,-166.393 583.198,-170.99 585.929,-167.154 582.513,-167.915 582.513,-167.915 582.513,-167.915 585.929,-167.154 581.828,-164.84 589.345,-166.393 589.345,-166.393\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"555.67\" y=\"-180.8\">{a}</text>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g class=\"node\" id=\"node7\"><title>6</title>\n",
"<ellipse cx=\"774.857\" cy=\"-158\" fill=\"#ffffaa\" rx=\"37.4556\" ry=\"37.4556\" stroke=\"black\"/>\n",
"<ellipse cx=\"774.857\" cy=\"-158\" fill=\"none\" rx=\"41.4533\" ry=\"41.4533\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"774.857\" y=\"-161.8\">0</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"774.857\" y=\"-146.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;6 -->\n",
"<g class=\"edge\" id=\"edge6\"><title>2-&gt;6</title>\n",
"<path d=\"M514.661,-209.497C551.574,-229.937 614.593,-256.796 667.38,-239 694.942,-229.708 721.017,-210.125 740.465,-192.542\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"745.771,-187.646 742.763,-194.708 743.199,-190.02 740.627,-192.393 740.627,-192.393 740.627,-192.393 743.199,-190.02 738.49,-190.078 745.771,-187.646 745.771,-187.646\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"628.025\" y=\"-248.8\">{}</text>\n",
"</g>\n",
"<!-- 7 -->\n",
"<g class=\"node\" id=\"node8\"><title>7</title>\n",
"<ellipse cx=\"926.639\" cy=\"-61\" fill=\"#ffffaa\" rx=\"37.4556\" ry=\"37.4556\" stroke=\"black\"/>\n",
"<ellipse cx=\"926.639\" cy=\"-61\" fill=\"none\" rx=\"41.4533\" ry=\"41.4533\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"926.639\" y=\"-64.8\">0</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"926.639\" y=\"-49.8\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;7 -->\n",
"<g class=\"edge\" id=\"edge7\"><title>2-&gt;7</title>\n",
"<path d=\"M510.516,-164.88C530.742,-147.339 559.75,-124.548 588.67,-110 683.063,-62.5163 809.91,-57.452 877.879,-58.7202\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"885.07,-58.8824 878.001,-61.8737 881.571,-58.8034 878.072,-58.7245 878.072,-58.7245 878.072,-58.7245 881.571,-58.8034 878.143,-55.5753 885.07,-58.8824 885.07,-58.8824\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"700.38\" y=\"-80.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 8 -->\n",
"<g class=\"node\" id=\"node9\"><title>8</title>\n",
"<ellipse cx=\"926.639\" cy=\"-289\" fill=\"#ffffaa\" rx=\"40.1285\" ry=\"40.1285\" stroke=\"black\"/>\n",
"<ellipse cx=\"926.639\" cy=\"-289\" fill=\"none\" rx=\"44.111\" ry=\"44.111\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"926.639\" y=\"-292.8\">0</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"926.639\" y=\"-277.8\">!a &amp; !b</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;8 -->\n",
"<g class=\"edge\" id=\"edge8\"><title>2-&gt;8</title>\n",
"<path d=\"M508.636,-216.791C518.105,-225.87 529.33,-235.58 540.67,-243 560.155,-255.749 566.391,-257.228 588.67,-264 693.763,-295.945 724.494,-290.456 834.334,-291 847.667,-291.066 851.002,-291.217 864.334,-291 867.837,-290.943 871.453,-290.867 875.095,-290.779\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"882.106,-290.595 875.191,-293.928 878.607,-290.687 875.108,-290.779 875.108,-290.779 875.108,-290.779 878.607,-290.687 875.026,-287.63 882.106,-290.595 882.106,-290.595\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"700.38\" y=\"-292.8\">{b}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge14\"><title>3-&gt;2</title>\n",
"<path d=\"M227.758,-145.527C264.685,-139.647 325.2,-133.376 376.06,-144 399.22,-148.838 423.521,-159.065 442.935,-168.65\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"449.323,-171.868 441.655,-171.532 446.198,-170.293 443.072,-168.719 443.072,-168.719 443.072,-168.719 446.198,-170.293 444.489,-165.906 449.323,-171.868 449.323,-171.868\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"338.583\" y=\"-147.8\">{a}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge13\"><title>3-&gt;3</title>\n",
"<path d=\"M179.627,-185.086C179.558,-196.323 183.933,-205.355 192.751,-205.355 199.64,-205.355 203.817,-199.843 205.282,-192.073\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"205.875,-185.086 208.422,-192.327 205.579,-188.574 205.283,-192.061 205.283,-192.061 205.283,-192.061 205.579,-188.574 202.145,-191.795 205.875,-185.086 205.875,-185.086\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"192.751\" y=\"-209.155\">{}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge15\"><title>3-&gt;4</title>\n",
"<path d=\"M222.222,-171.683C229.739,-176.234 238.017,-180.702 246.106,-184 261.284,-190.188 278.659,-194.756 294.16,-198.021\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"301.135,-199.43 293.65,-201.131 297.705,-198.737 294.274,-198.044 294.274,-198.044 294.274,-198.044 297.705,-198.737 294.898,-194.956 301.135,-199.43 301.135,-199.43\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"264.606\" y=\"-199.8\">{b}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge9\"><title>3-&gt;5</title>\n",
"<path d=\"M226.397,-140.622C232.858,-138.77 239.641,-137.1 246.106,-136 366.378,-115.533 510.752,-135.902 582.298,-148.943\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"589.408,-150.259 581.951,-152.082 585.966,-149.622 582.525,-148.985 582.525,-148.985 582.525,-148.985 585.966,-149.622 583.098,-145.887 589.408,-150.259 589.408,-150.259\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"409.06\" y=\"-133.8\">{}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;6 -->\n",
"<g class=\"edge\" id=\"edge10\"><title>3-&gt;6</title>\n",
"<path d=\"M224.377,-135.817C231.353,-132.741 238.851,-129.896 246.106,-128 427.419,-80.611 484.163,-70.6112 667.38,-110 689.822,-114.825 713.237,-124.768 732.376,-134.36\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"738.695,-137.592 731.028,-137.209 735.579,-135.998 732.463,-134.405 732.463,-134.405 732.463,-134.405 735.579,-135.998 733.897,-131.6 738.695,-137.592 738.695,-137.592\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"482.365\" y=\"-91.8\">{a}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;7 -->\n",
"<g class=\"edge\" id=\"edge11\"><title>3-&gt;7</title>\n",
"<path d=\"M207.136,-119.392C227.894,-74.7296 272.369,-0 337.583,-0 337.583,-0 337.583,-0 775.857,-0 815.143,-0 856.228,-18.222 885.41,-34.7474\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"891.821,-38.4592 884.185,-37.6779 888.792,-36.7055 885.763,-34.9518 885.763,-34.9518 885.763,-34.9518 888.792,-36.7055 887.342,-32.2257 891.821,-38.4592 891.821,-38.4592\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"555.67\" y=\"-3.8\">{b}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;8 -->\n",
"<g class=\"edge\" id=\"edge12\"><title>3-&gt;8</title>\n",
"<path d=\"M209.097,-183.411C215.207,-196.222 222.181,-211.233 228.106,-225 257.834,-294.071 262.386,-354 337.583,-354 337.583,-354 337.583,-354 775.857,-354 814.76,-354 854.998,-335.32 883.959,-317.988\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"889.963,-314.317 885.634,-320.656 886.977,-316.142 883.991,-317.968 883.991,-317.968 883.991,-317.968 886.977,-316.142 882.348,-315.281 889.963,-314.317 889.963,-314.317\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"555.67\" y=\"-357.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 9 -->\n",
"<g class=\"node\" id=\"node10\"><title>9</title>\n",
"<ellipse cx=\"482.365\" cy=\"-286\" fill=\"#ffffaa\" rx=\"40.1111\" ry=\"40.1111\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"482.365\" y=\"-289.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"482.365\" y=\"-274.8\">!a &amp; !b</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;9 -->\n",
"<g class=\"edge\" id=\"edge16\"><title>3-&gt;9</title>\n",
"<path d=\"M208.952,-183.615C226.27,-215.577 257.875,-263.141 301.106,-284 343.123,-304.273 397.325,-301.615 435.276,-295.857\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"442.641,-294.67 436.231,-298.894 439.186,-295.227 435.73,-295.784 435.73,-295.784 435.73,-295.784 439.186,-295.227 435.229,-292.674 442.641,-294.67 442.641,-294.67\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"338.583\" y=\"-302.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge18\"><title>4-&gt;2</title>\n",
"<path d=\"M376.095,-201.137C394.949,-199.143 418.082,-196.695 437.857,-194.603\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"444.976,-193.85 438.346,-197.719 441.496,-194.218 438.015,-194.586 438.015,-194.586 438.015,-194.586 441.496,-194.218 437.684,-191.454 444.976,-193.85 444.976,-193.85\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"409.06\" y=\"-202.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge17\"><title>4-&gt;3</title>\n",
"<path d=\"M309.772,-180.571C301.655,-174.596 292.444,-168.826 283.106,-165 268.272,-158.921 251.03,-155.624 235.672,-153.857\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"228.302,-153.107 235.585,-150.682 231.784,-153.461 235.266,-153.816 235.266,-153.816 235.266,-153.816 231.784,-153.461 234.947,-156.95 228.302,-153.107 228.302,-153.107\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"264.606\" y=\"-168.8\">{b}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge19\"><title>4-&gt;4</title>\n",
"<path d=\"M325.461,-240.213C325.596,-251.517 329.97,-260.477 338.583,-260.477 345.312,-260.477 349.454,-255.008 351.008,-247.226\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"351.705,-240.213 354.147,-247.49 351.359,-243.696 351.012,-247.179 351.012,-247.179 351.012,-247.179 351.359,-243.696 347.878,-246.867 351.705,-240.213 351.705,-240.213\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"338.583\" y=\"-264.277\">{}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;9 -->\n",
"<g class=\"edge\" id=\"edge20\"><title>4-&gt;9</title>\n",
"<path d=\"M371.402,-223.178C391.924,-234.903 418.8,-250.257 440.845,-262.851\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"446.925,-266.325 439.285,-265.587 443.886,-264.589 440.847,-262.852 440.847,-262.852 440.847,-262.852 443.886,-264.589 442.41,-260.117 446.925,-266.325 446.925,-266.325\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"409.06\" y=\"-256.8\">{a}</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge21\"><title>5-&gt;5</title>\n",
"<path d=\"M614.546,-195.236C614.884,-206.528 619.377,-215.355 628.025,-215.355 634.782,-215.355 639.002,-209.968 640.686,-202.226\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"641.505,-195.236 643.819,-202.555 641.098,-198.712 640.691,-202.189 640.691,-202.189 640.691,-202.189 641.098,-198.712 637.562,-201.822 641.505,-195.236 641.505,-195.236\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"628.025\" y=\"-219.155\">{}</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;6 -->\n",
"<g class=\"edge\" id=\"edge22\"><title>5-&gt;6</title>\n",
"<path d=\"M666.037,-146.689C672.431,-145.156 679.056,-143.827 685.38,-143 698.601,-141.271 702.152,-141.33 715.38,-143 719.444,-143.513 723.629,-144.219 727.805,-145.047\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"734.8,-146.543 727.296,-148.159 731.377,-145.811 727.955,-145.078 727.955,-145.078 727.955,-145.078 731.377,-145.811 728.613,-141.998 734.8,-146.543 734.8,-146.543\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"700.38\" y=\"-146.8\">{a}</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;7 -->\n",
"<g class=\"edge\" id=\"edge23\"><title>5-&gt;7</title>\n",
"<path d=\"M659.754,-134.347C679.693,-120.18 706.822,-103.027 733.38,-93 780.616,-75.1666 838.104,-67.2507 877.845,-63.7498\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"885.052,-63.146 878.34,-66.8694 881.565,-63.4382 878.077,-63.7304 878.077,-63.7304 878.077,-63.7304 881.565,-63.4382 877.814,-60.5914 885.052,-63.146 885.052,-63.146\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"774.857\" y=\"-96.8\">{b}</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;8 -->\n",
"<g class=\"edge\" id=\"edge24\"><title>5-&gt;8</title>\n",
"<path d=\"M656.84,-185.638C676.645,-203.852 704.731,-226.867 733.38,-241 778.691,-263.352 835.286,-275.855 875.308,-282.454\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"882.581,-283.618 875.171,-285.622 879.125,-283.065 875.669,-282.512 875.669,-282.512 875.669,-282.512 879.125,-283.065 876.167,-279.401 882.581,-283.618 882.581,-283.618\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"774.857\" y=\"-274.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge25\"><title>6-&gt;5</title>\n",
"<path d=\"M733.217,-158C715.031,-158 693.51,-158 674.762,-158\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"667.457,-158 674.457,-154.85 670.957,-158 674.457,-158 674.457,-158 674.457,-158 670.957,-158 674.457,-161.15 667.457,-158 667.457,-158\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"700.38\" y=\"-161.8\">{a}</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;6 -->\n",
"<g class=\"edge\" id=\"edge26\"><title>6-&gt;6</title>\n",
"<path d=\"M761.024,-197.182C761.502,-208.618 766.113,-217.477 774.857,-217.477 781.688,-217.477 785.997,-212.07 787.784,-204.251\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"788.691,-197.182 790.924,-204.526 788.245,-200.654 787.8,-204.125 787.8,-204.125 787.8,-204.125 788.245,-200.654 784.675,-203.724 788.691,-197.182 788.691,-197.182\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"774.857\" y=\"-221.277\">{}</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;7 -->\n",
"<g class=\"edge\" id=\"edge27\"><title>6-&gt;7</title>\n",
"<path d=\"M810.22,-135.746C832.578,-121.267 861.832,-102.322 885.294,-87.1277\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"891.436,-83.1502 887.273,-89.5993 888.498,-85.0527 885.56,-86.9553 885.56,-86.9553 885.56,-86.9553 888.498,-85.0527 883.848,-84.3113 891.436,-83.1502 891.436,-83.1502\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"849.334\" y=\"-122.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;8 -->\n",
"<g class=\"edge\" id=\"edge28\"><title>6-&gt;8</title>\n",
"<path d=\"M806.529,-184.826C829.843,-205.216 862.064,-233.397 887.115,-255.307\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"892.669,-260.165 885.327,-257.927 890.035,-257.861 887.4,-255.556 887.4,-255.556 887.4,-255.556 890.035,-257.861 889.474,-253.185 892.669,-260.165 892.669,-260.165\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"849.334\" y=\"-239.8\">{b}</text>\n",
"</g>\n",
"</g>\n",
"</svg>"
],
"text": [
"<IPython.core.display.SVG at 0x7f2e80d6fc50>"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, remove dead states, and remove stuttering transitions (i.e., transitions labeled by `{}`), marking as *livelock accepting* (rectangles) any states from which there exists a an accepting path labeled by `{}`."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ta = spot.tgba_to_ta(a, propset, True, True, False, False, False)\n",
"ta.show('.A')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"svg": [
"<svg height=\"161pt\" viewBox=\"0.00 0.00 715.35 161.00\" width=\"715pt\" 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 157)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" points=\"-4,4 -4,-157 711.349,-157 711.349,4 -4,4\" stroke=\"none\"/>\n",
"<!-- 0 -->\n",
"<!-- 1 -->\n",
"<g class=\"node\" id=\"node2\"><title>1</title>\n",
"<ellipse cx=\"62.6978\" cy=\"-68\" fill=\"#ffffaa\" rx=\"24.8972\" ry=\"24.8972\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"62.6978\" y=\"-64.3\">init</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g class=\"edge\" id=\"edge1\"><title>0-&gt;1</title>\n",
"<path d=\"M1.04399,-68C1.93865,-68 16.3331,-68 30.8732,-68\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"37.9642,-68 30.9643,-71.1501 34.4642,-68 30.9642,-68.0001 30.9642,-68.0001 30.9642,-68.0001 34.4642,-68 30.9642,-64.8501 37.9642,-68 37.9642,-68\" stroke=\"black\"/>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g class=\"node\" id=\"node3\"><title>2</title>\n",
"<polygon fill=\"#ffffaa\" points=\"479.349,-148 425.349,-148 425.349,-110 479.349,-110 479.349,-148\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"452.349\" y=\"-132.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"452.349\" y=\"-117.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge2\"><title>1-&gt;2</title>\n",
"<path d=\"M85.1066,-78.4223C91.5527,-81.3783 98.6955,-84.476 105.396,-87 183.158,-116.294 202.189,-128.87 284.396,-141 317.351,-145.863 326.044,-141.694 359.349,-141 380.696,-140.555 386.184,-141.822 407.349,-139 410.85,-138.533 414.484,-137.92 418.093,-137.228\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"424.966,-135.815 418.744,-140.31 421.537,-136.52 418.109,-137.225 418.109,-137.225 418.109,-137.225 421.537,-136.52 417.475,-134.139 424.966,-135.815 424.966,-135.815\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"247.896\" y=\"-141.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g class=\"node\" id=\"node4\"><title>3</title>\n",
"<polygon fill=\"#ffffaa\" points=\"211.396,-87 157.396,-87 157.396,-49 211.396,-49 211.396,-87\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"184.396\" y=\"-71.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"184.396\" y=\"-56.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge3\"><title>1-&gt;3</title>\n",
"<path d=\"M87.6328,-68C105.497,-68 130.135,-68 149.947,-68\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"157.006,-68 150.006,-71.1501 153.506,-68 150.006,-68.0001 150.006,-68.0001 150.006,-68.0001 153.506,-68 150.006,-64.8501 157.006,-68 157.006,-68\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"122.396\" y=\"-71.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g class=\"node\" id=\"node5\"><title>4</title>\n",
"<ellipse cx=\"321.872\" cy=\"-65\" fill=\"#ffffaa\" rx=\"37.4533\" ry=\"37.4533\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"321.872\" y=\"-68.8\">1</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"321.872\" y=\"-53.8\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge4\"><title>1-&gt;4</title>\n",
"<path d=\"M84.3656,-55.3514C102.769,-44.8778 130.817,-30.8075 157.396,-25 199.902,-15.7122 248.27,-30.763 281.299,-44.9807\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"288.106,-47.9929 280.43,-48.041 284.905,-46.5767 281.705,-45.1604 281.705,-45.1604 281.705,-45.1604 284.905,-46.5767 282.979,-42.2798 288.106,-47.9929 288.106,-47.9929\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"184.396\" y=\"-28.8\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g class=\"node\" id=\"node6\"><title>5</title>\n",
"<polygon fill=\"#ffffaa\" points=\"589.349,-123 535.349,-123 535.349,-85 589.349,-85 589.349,-123\" stroke=\"black\"/>\n",
"<polygon fill=\"none\" points=\"593.349,-127 531.349,-127 531.349,-81 593.349,-81 593.349,-127\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"562.349\" y=\"-107.8\">0</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"562.349\" y=\"-92.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge5\"><title>2-&gt;5</title>\n",
"<path d=\"M479.493,-122.948C492.905,-119.844 509.474,-116.008 524.19,-112.602\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"531.242,-110.969 525.133,-115.617 527.833,-111.758 524.423,-112.548 524.423,-112.548 524.423,-112.548 527.833,-111.758 523.712,-109.479 531.242,-110.969 531.242,-110.969\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"505.349\" y=\"-121.8\">{a}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge7\"><title>3-&gt;2</title>\n",
"<path d=\"M211.569,-81.698C231.123,-91.3492 258.782,-103.791 284.396,-111 324.55,-122.302 335.856,-119.702 377.349,-124 390.625,-125.375 405.282,-126.456 418.026,-127.256\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"425.283,-127.695 418.105,-130.417 421.789,-127.484 418.295,-127.273 418.295,-127.273 418.295,-127.273 421.789,-127.484 418.485,-124.128 425.283,-127.695 425.283,-127.695\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"321.872\" y=\"-125.8\">{a}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge8\"><title>3-&gt;4</title>\n",
"<path d=\"M211.405,-55.4294C217.198,-53.1796 223.403,-51.1784 229.396,-50 245.554,-46.8226 263.411,-48.582 279.026,-51.8391\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"286.029,-53.4287 278.505,-54.951 282.616,-52.6539 279.203,-51.8791 279.203,-51.8791 279.203,-51.8791 282.616,-52.6539 279.9,-48.8073 286.029,-53.4287 286.029,-53.4287\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"247.896\" y=\"-53.8\">{b}</text>\n",
"</g>\n",
"<!-- 6 -->\n",
"<g class=\"node\" id=\"node7\"><title>6</title>\n",
"<polygon fill=\"#ffffaa\" points=\"703.349,-85 649.349,-85 649.349,-47 703.349,-47 703.349,-85\" stroke=\"black\"/>\n",
"<polygon fill=\"none\" points=\"707.349,-89 645.349,-89 645.349,-43 707.349,-43 707.349,-89\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"676.349\" y=\"-69.8\">0</text>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"676.349\" y=\"-54.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;6 -->\n",
"<g class=\"edge\" id=\"edge6\"><title>3-&gt;6</title>\n",
"<path d=\"M207.657,-48.6958C233.192,-28.592 277.186,-0 320.872,-0 320.872,-0 320.872,-0 563.349,-0 595.255,-0 626.076,-20.1262 647.282,-38.1505\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"652.73,-42.9164 645.387,-40.6786 650.096,-40.612 647.461,-38.3076 647.461,-38.3076 647.461,-38.3076 650.096,-40.612 649.535,-35.9367 652.73,-42.9164 652.73,-42.9164\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"452.349\" y=\"-3.8\">{a}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge10\"><title>4-&gt;2</title>\n",
"<path d=\"M355.625,-81.3155C374.995,-90.9647 399.44,-103.142 418.778,-112.775\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"425.126,-115.937 417.456,-115.635 421.993,-114.376 418.86,-112.816 418.86,-112.816 418.86,-112.816 421.993,-114.376 420.265,-109.996 425.126,-115.937 425.126,-115.937\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"392.349\" y=\"-109.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge9\"><title>4-&gt;3</title>\n",
"<path d=\"M284.333,-65.8091C263.851,-66.2627 238.5,-66.824 218.588,-67.265\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"211.517,-67.4216 218.445,-64.1173 215.016,-67.344 218.515,-67.2665 218.515,-67.2665 218.515,-67.2665 215.016,-67.344 218.585,-70.4157 211.517,-67.4216 211.517,-67.4216\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"247.896\" y=\"-70.8\">{b}</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;6 -->\n",
"<g class=\"edge\" id=\"edge11\"><title>5-&gt;6</title>\n",
"<path d=\"M587.188,-80.8632C594.396,-75.2601 602.707,-70.0196 611.349,-67 619.709,-64.0787 629.067,-62.8793 637.99,-62.6129\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"645.027,-62.5842 638.04,-65.7628 641.527,-62.5985 638.027,-62.6128 638.027,-62.6128 638.027,-62.6128 641.527,-62.5985 638.014,-59.4629 645.027,-62.5842 645.027,-62.5842\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"619.349\" y=\"-70.8\">{a}</text>\n",
"</g>\n",
"<!-- 6&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge12\"><title>6-&gt;5</title>\n",
"<path d=\"M645.252,-76.2114C631.432,-80.9005 614.911,-86.5056 600.339,-91.4496\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"593.363,-93.8167 598.98,-88.5846 596.677,-92.6921 599.992,-91.5676 599.992,-91.5676 599.992,-91.5676 596.677,-92.6921 601.004,-94.5505 593.363,-93.8167 593.363,-93.8167\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"619.349\" y=\"-90.8\">{a}</text>\n",
"</g>\n",
"</g>\n",
"</svg>"
],
"text": [
"<IPython.core.display.SVG at 0x7f2e89e119b0>"
]
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, use bisimulation to minimize the number of states."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"spot.minimize_ta(ta).show('.A')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 5,
"svg": [
"<svg height=\"178pt\" viewBox=\"0.00 0.00 562.40 178.00\" width=\"562pt\" 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 174)\">\n",
"<title>G</title>\n",
"<polygon fill=\"white\" points=\"-4,4 -4,-174 558.396,-174 558.396,4 -4,4\" stroke=\"none\"/>\n",
"<!-- 0 -->\n",
"<!-- 1 -->\n",
"<g class=\"node\" id=\"node2\"><title>1</title>\n",
"<ellipse cx=\"62.6978\" cy=\"-144\" fill=\"#ffffaa\" rx=\"24.8972\" ry=\"24.8972\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"62.6978\" y=\"-140.3\">init</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g class=\"edge\" id=\"edge1\"><title>0-&gt;1</title>\n",
"<path d=\"M1.04399,-144C1.93865,-144 16.3331,-144 30.8732,-144\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"37.9642,-144 30.9643,-147.15 34.4642,-144 30.9642,-144 30.9642,-144 30.9642,-144 34.4642,-144 30.9642,-140.85 37.9642,-144 37.9642,-144\" stroke=\"black\"/>\n",
"</g>\n",
"<!-- 2 -->\n",
"<g class=\"node\" id=\"node3\"><title>2</title>\n",
"<polygon fill=\"#ffffaa\" points=\"440.396,-84 386.396,-84 386.396,-48 440.396,-48 440.396,-84\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"413.396\" y=\"-62.3\">2</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge2\"><title>1-&gt;2</title>\n",
"<path d=\"M86.9099,-150.505C92.8863,-151.92 99.3405,-153.225 105.396,-154 200.719,-166.201 229.01,-160.734 320.396,-131 342.539,-123.795 349.163,-123.127 368.396,-110 376.786,-104.273 384.949,-96.8174 391.919,-89.675\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"397.001,-84.3081 394.476,-91.5568 394.595,-86.8495 392.188,-89.3909 392.188,-89.3909 392.188,-89.3909 394.595,-86.8495 389.901,-87.225 397.001,-84.3081 397.001,-84.3081\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"247.896\" y=\"-158.8\">!a &amp; b</text>\n",
"</g>\n",
"<!-- 3 -->\n",
"<g class=\"node\" id=\"node4\"><title>3</title>\n",
"<polygon fill=\"#ffffaa\" points=\"211.396,-94 157.396,-94 157.396,-58 211.396,-58 211.396,-94\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"184.396\" y=\"-72.3\">3</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge3\"><title>1-&gt;3</title>\n",
"<path d=\"M83.2503,-129.536C90.1123,-124.694 97.9646,-119.411 105.396,-115 119.96,-106.355 136.69,-97.8185 150.912,-90.9462\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"157.253,-87.9113 152.299,-93.7747 154.096,-89.4223 150.939,-90.9333 150.939,-90.9333 150.939,-90.9333 154.096,-89.4223 149.579,-88.092 157.253,-87.9113 157.253,-87.9113\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"122.396\" y=\"-118.8\">a &amp; b</text>\n",
"</g>\n",
"<!-- 4 -->\n",
"<g class=\"node\" id=\"node5\"><title>4</title>\n",
"<ellipse cx=\"302.396\" cy=\"-104\" fill=\"#ffffaa\" rx=\"18\" ry=\"18\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"302.396\" y=\"-100.3\">1</text>\n",
"</g>\n",
"<!-- 1&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge4\"><title>1-&gt;4</title>\n",
"<path d=\"M87.4738,-142.898C125.721,-140.694 203.038,-134.451 266.396,-118 270.535,-116.925 274.841,-115.487 278.96,-113.941\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"285.651,-111.282 280.309,-116.794 282.399,-112.575 279.146,-113.867 279.146,-113.867 279.146,-113.867 282.399,-112.575 277.983,-110.94 285.651,-111.282 285.651,-111.282\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"184.396\" y=\"-139.8\">a &amp; !b</text>\n",
"</g>\n",
"<!-- 5 -->\n",
"<g class=\"node\" id=\"node6\"><title>5</title>\n",
"<polygon fill=\"#ffffaa\" points=\"550.396,-40 496.396,-40 496.396,-4 550.396,-4 550.396,-40\" stroke=\"black\"/>\n",
"<polygon fill=\"none\" points=\"554.396,-44 492.396,-44 492.396,-3.55271e-15 554.396,-3.55271e-15 554.396,-44\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"523.396\" y=\"-18.3\">4</text>\n",
"</g>\n",
"<!-- 2&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge5\"><title>2-&gt;5</title>\n",
"<path d=\"M440.539,-55.3488C454.074,-49.8349 470.822,-43.0113 485.637,-36.9757\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"492.289,-34.2656 486.995,-39.8239 489.048,-35.5862 485.807,-36.9067 485.807,-36.9067 485.807,-36.9067 489.048,-35.5862 484.618,-33.9895 492.289,-34.2656 492.289,-34.2656\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"466.396\" y=\"-51.8\">{a}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge7\"><title>3-&gt;2</title>\n",
"<path d=\"M211.404,-70.9547C217.306,-69.898 223.556,-68.8483 229.396,-68 269.507,-62.1732 279.873,-61.1195 320.396,-62 339.836,-62.4224 361.57,-63.3463 379.03,-64.1999\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"386.233,-64.5597 379.084,-67.3564 382.737,-64.385 379.241,-64.2103 379.241,-64.2103 379.241,-64.2103 382.737,-64.385 379.399,-61.0642 386.233,-64.5597 386.233,-64.5597\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"302.396\" y=\"-65.8\">{a}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;4 -->\n",
"<g class=\"edge\" id=\"edge8\"><title>3-&gt;4</title>\n",
"<path d=\"M211.657,-72.1843C227.874,-70.8265 248.862,-70.9018 266.396,-77 272.543,-79.1381 278.459,-82.823 283.622,-86.7951\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"289.305,-91.5145 281.908,-89.4661 286.613,-89.2786 283.92,-87.0426 283.92,-87.0426 283.92,-87.0426 286.613,-89.2786 285.932,-84.6192 289.305,-91.5145 289.305,-91.5145\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"247.896\" y=\"-80.8\">{b}</text>\n",
"</g>\n",
"<!-- 3&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge6\"><title>3-&gt;5</title>\n",
"<path d=\"M211.649,-65.47C217.427,-63.4301 223.564,-61.4721 229.396,-60 319.354,-37.2923 428.464,-27.7027 484.752,-24.03\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"492.008,-23.5705 485.221,-27.1567 488.515,-23.7917 485.022,-24.013 485.022,-24.013 485.022,-24.013 488.515,-23.7917 484.823,-20.8693 492.008,-23.5705 492.008,-23.5705\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"353.396\" y=\"-42.8\">{a}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge10\"><title>4-&gt;2</title>\n",
"<path d=\"M319.95,-98.2286C335.72,-92.7311 359.903,-84.3003 379.58,-77.4404\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"386.331,-75.0869 380.758,-80.3657 383.026,-76.2391 379.721,-77.3913 379.721,-77.3913 379.721,-77.3913 383.026,-76.2391 378.684,-74.4168 386.331,-75.0869 386.331,-75.0869\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"353.396\" y=\"-94.8\">{a, b}</text>\n",
"</g>\n",
"<!-- 4&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge9\"><title>4-&gt;3</title>\n",
"<path d=\"M284.335,-102.054C269.627,-100.164 247.903,-96.8631 229.396,-92 225.851,-91.0685 222.189,-89.9687 218.563,-88.7888\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"211.671,-86.4443 219.312,-85.7166 214.984,-87.5715 218.298,-88.6988 218.298,-88.6988 218.298,-88.6988 214.984,-87.5715 217.283,-91.6809 211.671,-86.4443 211.671,-86.4443\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"247.896\" y=\"-102.8\">{b}</text>\n",
"</g>\n",
"<!-- 5&#45;&gt;5 -->\n",
"<g class=\"edge\" id=\"edge11\"><title>5-&gt;5</title>\n",
"<path d=\"M513.021,-44.2124C512.172,-53.7952 515.63,-62 523.396,-62 529.098,-62 532.478,-57.5751 533.535,-51.4291\" fill=\"none\" stroke=\"black\"/>\n",
"<polygon fill=\"black\" points=\"533.77,-44.2124 536.69,-51.3112 533.656,-47.7105 533.542,-51.2086 533.542,-51.2086 533.542,-51.2086 533.656,-47.7105 530.394,-51.1061 533.77,-44.2124 533.77,-44.2124\" stroke=\"black\"/>\n",
"<text font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"523.396\" y=\"-65.8\">{a}</text>\n",
"</g>\n",
"</g>\n",
"</svg>"
],
"text": [
"<IPython.core.display.SVG at 0x7f2e884949e8>"
]
}
],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}