Commit 6a808492 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

python: implicit str->formula conversion

* python/spot/impl.i, python/spot/__init__.py: Implement it.
* NEWS: Mention it.
* tests/python/atva16-fig2a.ipynb, tests/python/atva16-fig2b.ipynb,
tests/python/formulas.ipynb, tests/python/ltsmin-dve.ipynb,
tests/python/ltsmin-pml.ipynb, tests/python/stutter-inv.ipynb,
doc/org/tut02.org: Modernize.
parent 5c1d9c49
......@@ -81,6 +81,10 @@ New in spot 2.5.3.dev (not yet released)
See https://spot.lrde.epita.fr/ipynb/alternation.html for some
examples.
- Strings are now implicitely converted into formulas when passed
as arguments to functions that expect formulas. Previously this
was done only for a few functions.
Bugs fixed:
- print_dot() will correctly escape strings containing \n in HTML
......
......@@ -62,18 +62,17 @@ pairs of atomic propositions of the form (new-name, old-name).
#+BEGIN_SRC python :results output :exports both
import spot
f = spot.formula('"Proc@Here" U ("var > 10" | "var < 4")')
m = spot.relabeling_map()
g = spot.relabel(f, spot.Pnn, m)
g = spot.relabel('"Proc@Here" U ("var > 10" | "var < 4")', spot.Pnn, m)
for newname, oldname in m.items():
print("#define {} ({})".format(newname.to_str(), oldname.to_str('spin', True)))
print(g.to_str('spin', True))
#+END_SRC
#+RESULTS:
: #define p0 ((Proc@Here))
: #define p1 ((var < 4))
: #define p2 ((var > 10))
: #define p0 (Proc@Here)
: #define p1 (var < 4)
: #define p2 (var > 10)
: (p0) U ((p1) || (p2))
* C++
......
......@@ -675,26 +675,18 @@ def translate(formula, *args, dict=_bdd_dict):
formula.translate = translate
def contains(left, right):
from spot.impl import contains as contains_impl
if type(left) is str:
left = formula(left)
if type(right) is str:
right = formula(right)
return contains_impl(left, right)
def are_equivalent(left, right):
from spot.impl import are_equivalent as equiv
if type(left) is str:
left = formula(left)
if type(right) is str:
right = formula(right)
return equiv(left, right)
formula.contains = contains
formula.equivalent_to = are_equivalent
twa.contains = contains
twa.equivalent_to = are_equivalent
# Wrap C++-functions into lambdas so that they get converted into
# instance methods (i.e., self passed as first argument
# automatically), because only user-defined functions are converted as
# instance methods.
def _add_formula(meth, name = None):
setattr(formula, name or meth, (lambda self, *args, **kwargs:
globals()[meth](self, *args, **kwargs)))
_add_formula('contains')
_add_formula('are_equivalent', 'equivalent_to')
def postprocess(automaton, *args, formula=None):
"""Post process an automaton.
......
......@@ -365,7 +365,8 @@ namespace swig
// default to None on the Python side.
%typemap(in) spot::formula {
void *tmp;
int res = SWIG_ConvertPtr($input, &tmp, $descriptor(spot::formula*), 0);
int res = SWIG_ConvertPtr($input, &tmp, $descriptor(spot::formula*),
SWIG_POINTER_IMPLICIT_CONV);
if (!SWIG_IsOK(res)) {
%argument_fail(res, "spot::formula", $symname, $argnum);
}
......@@ -377,9 +378,10 @@ namespace swig
// if tmp == nullptr, then the default value of $1 is fine.
}
%typemap(typecheck) spot::formula {
%typemap(typecheck, precedence=2000) spot::formula {
$1 = SWIG_CheckState(SWIG_ConvertPtr($input, nullptr,
$descriptor(spot::formula*), 0));
$descriptor(spot::formula*),
SWIG_POINTER_IMPLICIT_CONV));
}
%typemap(out) spot::formula {
......@@ -427,6 +429,7 @@ namespace swig
%include <spot/misc/trival.hh>
%implicitconv std::vector<spot::formula>;
%implicitconv spot::formula;
%include <spot/tl/formula.hh>
......
{
"cells": [
{
 
"cell_type": "markdown",
"metadata": {},
"source": [
"This example is the left part of Fig.2 in our ATVA'16 paper titled [\"*Spot 2.0 — a framework for LTL and ω-automata manipulation*\"](https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf), slightly updated to the current version of Spot."
]
 
 
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
......@@ -27,18 +27,18 @@
"text/latex": [
"$\\mathsf{G} \\mathsf{F} a \\leftrightarrow \\mathsf{G} \\mathsf{F} b$"
],
"text/plain": [
"GFa <-> GFb"
 
 
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
 
 
"f = spot.formula('GFa <-> GFb'); f"
]
},
{
"cell_type": "code",
......
{
"cells": [
{
 
"cell_type": "markdown",
"metadata": {},
"source": [
"This example is the right part of Fig.2 in our ATVA'16 paper titled [\"*Spot 2.0 — a framework for LTL and ω-automata manipulation*\"](https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf) slightly updated to benefit from improvements in more recent versions of Spot."
]
},
 
 
 
 
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import spot\n",
......@@ -53,21 +53,20 @@
"text/plain": [
"ltsmin model with the following variables:\n",
" c: int\n",
" x1: int\n",
" x2: int\n",
 
 
 
 
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"adding"
}
],
"source": [
"adding"
]
},
{
"cell_type": "code",
......
......@@ -11,9 +11,7 @@
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"import spot"
......@@ -29,9 +27,7 @@
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -55,9 +51,7 @@
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -87,9 +81,7 @@
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -119,9 +111,7 @@
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -152,9 +142,7 @@
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -181,9 +169,7 @@
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
......@@ -214,9 +200,7 @@
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
......@@ -251,9 +235,7 @@
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
......@@ -316,9 +298,7 @@
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -338,9 +318,7 @@
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -367,9 +345,7 @@
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -389,9 +365,7 @@
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -411,9 +385,7 @@
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -440,9 +412,7 @@
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -465,9 +435,7 @@
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -490,9 +458,7 @@
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -522,9 +488,7 @@
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
......@@ -661,9 +625,7 @@
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -709,9 +671,7 @@
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -731,9 +691,7 @@
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -763,9 +721,7 @@
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -795,9 +751,7 @@
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -821,9 +775,7 @@
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"data": {
......@@ -853,9 +805,7 @@
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [
{
"name": "stdout",
......@@ -898,7 +848,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
"version": "3.6.5"
}
},
"nbformat": 4,
......
......@@ -151,11 +151,11 @@
"metadata": {},
"source": [
"Working with an ltsmin model\n",
"----------------------------\n",
"\n",
"Printing an ltsmin model shows some information about the variables it contains and their types, however the `info()` methods provide the data in a map that is easier to work with."
"Printing an ltsmin model shows some information about the variables it contains and their types, however the `info()` methods provide the data in a map that is easier to work with."
]
},
{
"cell_type": "code",
"execution_count": 7,
......@@ -175,31 +175,35 @@
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"m"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('state_size', 4),\n",
" ('types', [('int', []), ('P', ['x']), ('Q', ['wait', 'work'])]),\n",
 
 
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sorted(m.info().items())"
]
 
 
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To obtain a Kripke structure, call `kripke` and supply a list of atomic propositions to observe in the model."
......@@ -216,14 +220,13 @@
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
"<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n",
" -->\n",
"<!-- Pages: 1 -->\n",
"<svg width=\"734pt\" height=\"242pt\"\n",
" viewBox=\"0.00 0.00 734.00 242.46\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
"<g id=\"graph0\" class=\"graph\" transform=\"scale(.6487 .6487) rotate(0) translate(4 369.7401)\">\n",
"<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-369.7401 1127.4104,-369.7401 1127.4104,4 -4,4\"/>\n",
"<text text-anchor=\"start\" x=\"558.7052\" y=\"-350.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">t</text>\n",
"<text text-anchor=\"start\" x=\"550.7052\" y=\"-335.5401\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">[all]</text>\n",
"<!-- I -->\n",
......@@ -240,14 +243,13 @@
"<path fill=\"none\" stroke=\"#000000\" d=\"M1.1671,-154.8701C3.9097,-154.8701 14.8741,-154.8701 29.7057,-154.8701\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"36.7767,-154.8701 29.7767,-158.0202 33.2767,-154.8701 29.7767,-154.8702 29.7767,-154.8702 29.7767,-154.8702 33.2767,-154.8701 29.7766,-151.7202 36.7767,-154.8701 36.7767,-154.8701\"/>\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"</g>\n",
"<!-- 1 -->\n",
"<g id=\"node3\" class=\"node\">\n",
"<title>1</title>\n",
"<title>1</title>\n",
"<ellipse fill=\"#ffffaa\" stroke=\"#000000\" cx=\"415.2397\" cy=\"-190.8701\" rx=\"115.931\" ry=\"26.7407\"/>\n",
"<text text-anchor=\"start\" x=\"370.2397\" y=\"-194.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">a=1, b=0, Q=0</text>\n",
"<text text-anchor=\"start\" x=\"341.2397\" y=\"-179.6701\" font-family=\"Lato\" font-size=\"14.00\" fill=\"#000000\">!&quot;a&lt;1&quot; &amp; !&quot;b&gt;2&quot; &amp; !dead</text>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g id=\"edge2\" class=\"edge\">\n",
"<title>0&#45;&gt;1</title>\n",
......@@ -278,6 +280,6 @@
"<g id=\"edge4\" class=\"edge\">\n",
"<title>1&#45;&gt;3</title>\n",
"<path fill=\"none\" stroke=\"#000000\" d=\"M515.7696,-204.3776C535.2954,-207.0011 555.8335,-209.7607 575.576,-212.4133\"/>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"582.5231,-213.3467 575.1659,-215.5364 579.0543,-212.8806 575.5854,-212.4145 575.5854,-212.4145 575.5854,-212.4145 579.0543,-212.8806 576.0049,-209.2926 582.5231,-213.3467 582.5231,-213.3467\"/>\n",
"</g>\n",
"<polygon fill=\"#000000\" stroke=\"#000000\" points=\"582.5231,-213.3467 575.1659,-215.5364 579.0543,-212.8806 575.5854,-212.4145 575.5854,-212.4145 575.5854,-212.4145 579.0543,-212.8806 576.0049,-209.2926 582.5231,-213.3467 582.5231,-213.3467\"/>\n",
 
......
......@@ -60,11 +60,11 @@
"\n",
" [.......... ]\n",
" [.................... ]\n",
" [.............................. ]\n",
" [........................................ ]\n",
 
 
" Found 5 / 15 ( 33.3%) Guard/slot reads \n",
"\n",
" [......................... ]\n",
" [..................................................]\n",
" Found 6 / 6 (100.0%) Transition/slot tests \n",
......@@ -78,11 +78,11 @@
" Found 2, 4, 4 / 18 ( 11.1%, 22.2%, 22.2%) Actions/slot r,W,w \n",
"\n",
" [......................... ]\n",
" [..................................................]\n",
" Found 2, 4, 4 / 6 ( 33.3%, 66.7%, 66.7%) Atomics/slot r,W,w \n",
 
 
" [......................... ]\n",
" [..................................................]\n",
" Found 6, 4, 4 / 6 (100.0%, 66.7%, 66.7%) Transition/slot r,W,w \n",
"Generating transition/state dependency matrices done (0.0 sec)\n",
"\n",
......
%% Cell type:code id: tags:
``` python
import spot
spot.setup(show_default='.ban')
spot.setup(show_default='.bn')
from IPython.display import display
```
%% Cell type:markdown id: tags:
......@@ -151,11 +151,11 @@
``` python
def explain_stut(f):
f = spot.formula(f)
pos = spot.translate(f)
neg = spot.translate(spot.formula_Not(f))
neg = spot.translate(spot.formula.Not(f))
word = spot.product(spot.closure(pos), spot.closure(neg)).accepting_word()
if word is None:
print(f, "is stutter invariant")
return
word.simplify()
......@@ -192,11 +192,11 @@
%% Cell type:code id: tags:
``` python
f1 = spot.formula('F(a & X!a & XF(b & X!b & Ga))')
f2 = spot.formula('F(a & Xa & XXa & G!b)')
f = spot.formula_Or([f1, f2])
f = spot.formula.Or([f1, f2])
print(spot.is_stutter_invariant(f1))
print(spot.is_stutter_invariant(f2))
print(spot.is_stutter_invariant(f))
```
......@@ -259,11 +259,11 @@
%% Cell type:code id: tags:
``` python
g1 = spot.formula('GF(a & Xa) & GF!a')
g2 = spot.formula('!GF(a & Xa) & GF!a')
g = spot.formula_Or([g1, g2])
g = spot.formula.Or([g1, g2])
```
%% Cell type:code id: tags:
``` python
......@@ -405,11 +405,11 @@
State: 4 [!0] 3 {0 1}
State: 5 [0] 0 [0] 2
State: 6 [!0] 0
State: 7 [!0] 6 [0] 5
--END--""")
spot.highlight_stutter_invariant_states(ex1,None, 5)
spot.highlight_stutter_invariant_states(ex1, None, 5)
display(ex1)
```
%%%% Output: display_data
......@@ -489,18 +489,19 @@
fwd_closed = []
fmt = "{:40.40} {:>6} {:>8} {:>10}"
print(fmt.format("formula", "states", "SIstates", "fwd_closed"))
for f in formulas:
s = f.to_str()
aut = spot.translate(f)
aut_size.append(aut.num_states())
sistates = spot.stutter_invariant_states(aut, f)
sisz = sum(sistates)