python: cleanup with autopep8

* tests/python/341.py, tests/python/alarm.py, tests/python/bdddict.py,
tests/python/bddnqueen.py, tests/python/bugdet.py,
tests/python/dualize.py, tests/python/except.py, tests/python/gen.py,
tests/python/genem.py, tests/python/implies.py,
tests/python/interdep.py, tests/python/ipnbdoctest.py,
tests/python/kripke.py, tests/python/ltl2tgba.py,
tests/python/ltlf.py, tests/python/ltlparse.py,
tests/python/ltlsimple.py, tests/python/relabel.py,
tests/python/rs_like.py, tests/python/sccsplit.py,
tests/python/semidet.py, tests/python/setacc.py,
tests/python/setxor.py, tests/python/split.py,
tests/python/streett_totgba.py, tests/python/stutter.py,
tests/python/sum.py, tests/python/toparity.py, tests/python/toweak.py,
tests/python/trival.py, python/spot/__init__.py, python/spot/aux.py,
python/spot/jupyter.py: Reformat with autopep8.

fixup! * spot/tl/simplify.cc: Fix typos in tracing code.
This commit is contained in:
Alexandre Duret-Lutz 2019-07-02 10:12:44 +02:00
parent 5b01ce32dd
commit 822fe77891
33 changed files with 444 additions and 356 deletions

View file

@ -107,14 +107,17 @@ if 'op_ff' not in globals():
_bdd_dict = make_bdd_dict() _bdd_dict = make_bdd_dict()
__om_init_tmp = option_map.__init__ __om_init_tmp = option_map.__init__
def __om_init_new(self, str=None): def __om_init_new(self, str=None):
__om_init_tmp(self) __om_init_tmp(self)
if str: if str:
res = self.parse_options(str) res = self.parse_options(str)
if res: if res:
raise RuntimeError("failed to parse option at: '" + str +"'") raise RuntimeError("failed to parse option at: '" + str + "'")
option_map.__init__ = __om_init_new option_map.__init__ = __om_init_new
@ -162,6 +165,7 @@ class twa:
self.highlight_edge(val, color) self.highlight_edge(val, color)
return self return self
@_extend(twa) @_extend(twa)
class twa: class twa:
def to_str(a, format='hoa', opt=None): def to_str(a, format='hoa', opt=None):
@ -192,6 +196,7 @@ class twa:
f.write('\n') f.write('\n')
return a return a
@_extend(twa_graph) @_extend(twa_graph)
class twa_graph: class twa_graph:
def show_storage(self, opt=None): def show_storage(self, opt=None):
@ -200,12 +205,14 @@ class twa_graph:
from IPython.display import SVG from IPython.display import SVG
return SVG(_ostream_to_svg(ostr)) return SVG(_ostream_to_svg(ostr))
def make_twa_graph(*args): def make_twa_graph(*args):
from spot.impl import make_twa_graph as mtg from spot.impl import make_twa_graph as mtg
if len(args) == 0: if len(args) == 0:
return mtg(_bdd_dict) return mtg(_bdd_dict)
return mtg(*args) return mtg(*args)
@_extend(formula) @_extend(formula)
class formula: class formula:
def __init__(self, str): def __init__(self, str):
@ -243,8 +250,8 @@ class formula:
return str_sclatex_psl(self, parenth) return str_sclatex_psl(self, parenth)
elif format == 'mathjax' or format == 'j': elif format == 'mathjax' or format == 'j':
return (str_sclatex_psl(self, parenth). return (str_sclatex_psl(self, parenth).
replace("``", "\\unicode{x201C}"). replace("``", "\\unicode{x201C}").
replace("\\textrm{''}", "\\unicode{x201D}")) replace("\\textrm{''}", "\\unicode{x201D}"))
elif format == 'dot' or format == 'd': elif format == 'dot' or format == 'd':
ostr = ostringstream() ostr = ostringstream()
print_dot_psl(ostr, self) print_dot_psl(ostr, self)
@ -475,9 +482,9 @@ def automata(*sources, timeout=None, ignore_abort=True,
# universal_newlines for str output instead of bytes # universal_newlines for str output instead of bytes
# when the pipe is read from Python (which happens # when the pipe is read from Python (which happens
# when timeout is set). # when timeout is set).
prefn = None if no_sid else os.setsid
proc = subprocess.Popen(filename[:-1], shell=True, proc = subprocess.Popen(filename[:-1], shell=True,
preexec_fn= preexec_fn=prefn,
None if no_sid else os.setsid,
universal_newlines=True, universal_newlines=True,
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
if timeout is None: if timeout is None:
@ -751,7 +758,7 @@ formula.translate = translate
# instance methods (i.e., self passed as first argument # instance methods (i.e., self passed as first argument
# automatically), because only user-defined functions are converted as # automatically), because only user-defined functions are converted as
# instance methods. # instance methods.
def _add_formula(meth, name = None): def _add_formula(meth, name=None):
setattr(formula, name or meth, (lambda self, *args, **kwargs: setattr(formula, name or meth, (lambda self, *args, **kwargs:
globals()[meth](self, *args, **kwargs))) globals()[meth](self, *args, **kwargs)))
@ -811,10 +818,11 @@ twa.postprocess = postprocess
# instance methods (i.e., self passed as first argument # instance methods (i.e., self passed as first argument
# automatically), because only user-defined functions are converted as # automatically), because only user-defined functions are converted as
# instance methods. # instance methods.
def _add_twa_graph(meth, name = None): def _add_twa_graph(meth, name=None):
setattr(twa_graph, name or meth, (lambda self, *args, **kwargs: setattr(twa_graph, name or meth, (lambda self, *args, **kwargs:
globals()[meth](self, *args, **kwargs))) globals()[meth](self, *args, **kwargs)))
for meth in ('scc_filter', 'scc_filter_states', for meth in ('scc_filter', 'scc_filter_states',
'is_deterministic', 'is_unambiguous', 'is_deterministic', 'is_unambiguous',
'contains'): 'contains'):
@ -824,6 +832,8 @@ _add_twa_graph('are_equivalent', 'equivalent_to')
# Wrapper around a formula iterator to which we add some methods of formula # Wrapper around a formula iterator to which we add some methods of formula
# (using _addfilter and _addmap), so that we can write things like # (using _addfilter and _addmap), so that we can write things like
# formulas.simplify().is_X_free(). # formulas.simplify().is_X_free().
class formulaiterator: class formulaiterator:
def __init__(self, formulas): def __init__(self, formulas):
self._formulas = formulas self._formulas = formulas
@ -1003,14 +1013,14 @@ def simplify(f, **kwargs):
favor_event_univ = kwargs.get('favor_event_univ', False) favor_event_univ = kwargs.get('favor_event_univ', False)
simp_opts = tl_simplifier_options(basics, simp_opts = tl_simplifier_options(basics,
synt_impl, synt_impl,
event_univ, event_univ,
cont_checks, cont_checks,
cont_checks_stronger, cont_checks_stronger,
nenoform_stop_on_boolean, nenoform_stop_on_boolean,
reduce_size_strictly, reduce_size_strictly,
boolean_to_isop, boolean_to_isop,
favor_event_univ) favor_event_univ)
return tl_simplifier(simp_opts).simplify(f) return tl_simplifier(simp_opts).simplify(f)
@ -1025,14 +1035,13 @@ for fun in ['remove_x', 'relabel', 'relabel_bse',
_addmap(fun) _addmap(fun)
# Better interface to the corresponding C++ function. # Better interface to the corresponding C++ function.
def sat_minimize(aut, acc=None, colored=False, def sat_minimize(aut, acc=None, colored=False,
state_based=False, states=0, state_based=False, states=0,
max_states=0, sat_naive=False, sat_langmap=False, max_states=0, sat_naive=False, sat_langmap=False,
sat_incr=0, sat_incr_steps=0, sat_incr=0, sat_incr_steps=0,
display_log=False, return_log=False): display_log=False, return_log=False):
args='' args = ''
if acc is not None: if acc is not None:
if type(acc) is not str: if type(acc) is not str:
raise ValueError("argument 'acc' should be a string") raise ValueError("argument 'acc' should be a string")
@ -1079,16 +1088,19 @@ def parse_word(word, dic=_bdd_dict):
from spot.impl import parse_word as pw from spot.impl import parse_word as pw
return pw(word, dic) return pw(word, dic)
def bdd_to_formula(b, dic=_bdd_dict): def bdd_to_formula(b, dic=_bdd_dict):
from spot.impl import bdd_to_formula as bf from spot.impl import bdd_to_formula as bf
return bf(b, dic) return bf(b, dic)
def language_containment_checker(dic=_bdd_dict): def language_containment_checker(dic=_bdd_dict):
from spot.impl import language_containment_checker as c from spot.impl import language_containment_checker as c
c.contains = lambda this, a, b: c.contained(this, b, a) c.contains = lambda this, a, b: c.contained(this, b, a)
c.are_equivalent = lambda this, a, b: c.equal(this, a, b) c.are_equivalent = lambda this, a, b: c.equal(this, a, b)
return c(dic) return c(dic)
def mp_hierarchy_svg(cl=None): def mp_hierarchy_svg(cl=None):
""" """
Return an some string containing an SVG picture of the Manna & Return an some string containing an SVG picture of the Manna &
@ -1099,7 +1111,7 @@ def mp_hierarchy_svg(cl=None):
`mp_class(cl)`. `mp_class(cl)`.
""" """
if type(cl)==formula: if type(cl) == formula:
cl = mp_class(cl) cl = mp_class(cl)
ch = None ch = None
coords = { coords = {
@ -1112,12 +1124,12 @@ def mp_hierarchy_svg(cl=None):
'B': '110,198', 'B': '110,198',
} }
if cl in coords: if cl in coords:
highlight='''<g transform="translate({})"> highlight = '''<g transform="translate({})">
<line x1="-10" y1="-10" x2="10" y2="10" stroke="red" stroke-width="5" /> <line x1="-10" y1="-10" x2="10" y2="10" stroke="red" stroke-width="5" />
<line x1="-10" y1="10" x2="10" y2="-10" stroke="red" stroke-width="5" /> <line x1="-10" y1="10" x2="10" y2="-10" stroke="red" stroke-width="5" />
</g>'''.format(coords[cl]) </g>'''.format(coords[cl])
else: else:
highlight='' highlight = ''
return ''' return '''
<svg height="210" width="220" xmlns="http://www.w3.org/2000/svg" version="1.1"> <svg height="210" width="220" xmlns="http://www.w3.org/2000/svg" version="1.1">
<polygon points="20,0 200,120 200,210 20,210" fill="cyan" opacity=".2" /> <polygon points="20,0 200,120 200,210 20,210" fill="cyan" opacity=".2" />
@ -1150,8 +1162,10 @@ def show_mp_hierarchy(cl):
from IPython.display import SVG from IPython.display import SVG
return SVG(mp_hierarchy_svg(cl)) return SVG(mp_hierarchy_svg(cl))
formula.show_mp_hierarchy = show_mp_hierarchy formula.show_mp_hierarchy = show_mp_hierarchy
@_extend(twa_word) @_extend(twa_word)
class twa_word: class twa_word:
def _repr_latex_(self): def _repr_latex_(self):
@ -1162,8 +1176,8 @@ class twa_word:
res += '; ' res += '; '
res += bdd_to_formula(letter, bd).to_str('j') res += bdd_to_formula(letter, bd).to_str('j')
if len(res) > 1: if len(res) > 1:
res += '; '; res += '; '
res += '\\mathsf{cycle}\\{'; res += '\\mathsf{cycle}\\{'
for idx, letter in enumerate(self.cycle): for idx, letter in enumerate(self.cycle):
if idx: if idx:
res += '; ' res += '; '
@ -1201,7 +1215,7 @@ class twa_word:
'txt': 'text-anchor="start" font-size="20"', 'txt': 'text-anchor="start" font-size="20"',
'red': 'stroke="#ff0000" stroke-width="2"', 'red': 'stroke="#ff0000" stroke-width="2"',
'sml': 'text-anchor="start" font-size="10"' 'sml': 'text-anchor="start" font-size="10"'
} }
txt = ''' txt = '''
<svg height="{h3}" width="{w}" xmlns="http://www.w3.org/2000/svg" version="1.1"> <svg height="{h3}" width="{w}" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect x="0" y="0" width="{w}" height="{height}" fill="{bgcolor}"/> <rect x="0" y="0" width="{w}" height="{height}" fill="{bgcolor}"/>
@ -1236,11 +1250,11 @@ class twa_word:
if cur != 0: if cur != 0:
if last == -cur: if last == -cur:
txt += \ txt += \
('<line x1="{x}" y1="{y1}" x2="{x}" y2="{y2}" {red}/>' ('<line x1="{x}" y1="{y1}" x2="{x}" y2="{y2}" {red}/>'
.format(x=xpos*50, y1=ypos*50+5, .format(x=xpos*50, y1=ypos*50+5,
y2=ypos*50+45, **d)) y2=ypos*50+45, **d))
txt += \ txt += \
('<line x1="{x1}" y1="{y}" x2="{x2}" y2="{y}" {red}/>' ('<line x1="{x1}" y1="{y}" x2="{x2}" y2="{y}" {red}/>'
.format(x1=xpos*50, x2=(xpos+1)*50, .format(x1=xpos*50, x2=(xpos+1)*50,
y=ypos*50+25-20*cur, **d)) y=ypos*50+25-20*cur, **d))
last = cur last = cur
@ -1263,5 +1277,6 @@ class twa_word:
class scc_and_mark_filter: class scc_and_mark_filter:
def __enter__(self): def __enter__(self):
return self return self
def __exit__(self, exc_type, exc_value, traceback): def __exit__(self, exc_type, exc_value, traceback):
self.restore_acceptance() self.restore_acceptance()

View file

@ -28,6 +28,7 @@ import os
import errno import errno
import contextlib import contextlib
def extend(*classes): def extend(*classes):
""" """
Decorator that extends all the given classes with the contents Decorator that extends all the given classes with the contents
@ -89,6 +90,7 @@ def rm_f(filename):
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
raise raise
@contextlib.contextmanager @contextlib.contextmanager
def tmpdir(): def tmpdir():
cwd = os.getcwd() cwd = os.getcwd()

View file

@ -23,6 +23,7 @@ Auxiliary functions for Spot's Python bindings.
from IPython.display import display, HTML from IPython.display import display, HTML
def display_inline(*args, per_row=None, show=None): def display_inline(*args, per_row=None, show=None):
""" """
This is a wrapper around IPython's `display()` to display multiple This is a wrapper around IPython's `display()` to display multiple
@ -49,5 +50,5 @@ def display_inline(*args, per_row=None, show=None):
else: else:
rep = str(arg) rep = str(arg)
res += ("<div style='vertical-align:text-top;display:{};{}'>{}</div>" res += ("<div style='vertical-align:text-top;display:{};{}'>{}</div>"
.format(dpy, width, rep)) .format(dpy, width, rep))
display(HTML(res)) display(HTML(res))

View file

@ -20,6 +20,7 @@
import spot import spot
from subprocess import _active from subprocess import _active
def two_intersecting_automata(): def two_intersecting_automata():
"""return two random automata with a non-empty intersection""" """return two random automata with a non-empty intersection"""
g = spot.automata('randaut -A4 -Q5 -n-1 2 |') g = spot.automata('randaut -A4 -Q5 -n-1 2 |')
@ -27,9 +28,10 @@ def two_intersecting_automata():
if a.intersects(b): if a.intersects(b):
return a, b return a, b
for i in range(5): for i in range(5):
two_intersecting_automata() two_intersecting_automata()
n = len(_active) n = len(_active)
print(n, "active processes") print(n, "active processes")
assert(n == 0); assert(n == 0)

View file

@ -23,11 +23,13 @@ import signal
import sys import sys
import os import os
def alarm_handler(signum, frame): def alarm_handler(signum, frame):
sys.stdout.write("signaled\n") sys.stdout.write("signaled\n")
os.kill(child, signal.SIGTERM) os.kill(child, signal.SIGTERM)
exit(0) exit(0)
f = """!(G(F(P_Rbt2.observe)&& F(P_Rbt3.observe) && 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_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 || F(P_Rbt3.plus || P_Rbt3.moins || P_Rbt3.stop) && F(P_Rbt2.plus ||

View file

@ -20,6 +20,10 @@
# Make sure we can leep track of BDD association in Python using bdd_dict, as # Make sure we can leep track of BDD association in Python using bdd_dict, as
# discussed in issue #372. # discussed in issue #372.
import spot
class bdd_holder: class bdd_holder:
def __init__(self, aut): def __init__(self, aut):
self.bdddict = d = aut.get_dict() self.bdddict = d = aut.get_dict()
@ -48,10 +52,10 @@ class bdd_holder3:
self.bdddict.unregister_all_my_variables(self) self.bdddict.unregister_all_my_variables(self)
def check_ok(): def check_ok():
assert type(bdict.varnum(spot.formula.ap("a"))) is int assert type(bdict.varnum(spot.formula.ap("a"))) is int
def check_nok(): def check_nok():
try: try:
bdict.varnum(spot.formula.ap("a")) bdict.varnum(spot.formula.ap("a"))
@ -60,12 +64,13 @@ def check_nok():
else: else:
raise RuntimeError("missing exception") raise RuntimeError("missing exception")
def debug(txt): def debug(txt):
# print(txt) # print(txt)
# bdict.dump(spot.get_cout()) # bdict.dump(spot.get_cout())
pass pass
import spot
aut = spot.translate("a U b") aut = spot.translate("a U b")
bdict = aut.get_dict() bdict = aut.get_dict()
debug("aut") debug("aut")

View file

@ -1,5 +1,5 @@
# -*- mode: python; coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2010, 2011, 2012, 2014 Laboratoire de Recherche et # Copyright (C) 2010, 2011, 2012, 2014, 2019 Laboratoire de Recherche et
# Développement de l'EPITA. # Développement de l'EPITA.
# Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 # Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6
# (LIP6), département Systèmes Répartis Coopératifs (SRC), Université # (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
@ -26,9 +26,12 @@
import sys import sys
from buddy import * from buddy import *
# Build the requirements for all other fields than (i,j) assuming
# that (i,j) has a queen.
def build(i, j): def build(i, j):
"""
Build the requirements for all other fields than (i,j) assuming
that (i,j) has a queen.
"""
a = b = c = d = bddtrue a = b = c = d = bddtrue
# No one in the same column. # No one in the same column.
@ -59,7 +62,6 @@ def build(i, j):
queen &= a & b & c & d queen &= a & b & c & d
# Get the number of queens from the command-line, or default to 8. # Get the number of queens from the command-line, or default to 8.
if len(sys.argv) > 1: if len(sys.argv) > 1:
N = int(argv[1]) N = int(argv[1])
@ -97,7 +99,6 @@ solution = bdd_satone(queen)
bdd_printset(solution) bdd_printset(solution)
from spot import nl_cout from spot import nl_cout
nl_cout() nl_cout()
# Cleanup all BDD variables before calling bdd_done(), otherwise # Cleanup all BDD variables before calling bdd_done(), otherwise

View file

@ -73,7 +73,7 @@ State: 6 {0}
State: 7 {0} State: 7 {0}
[0&!1&2] 7 [0&!1&2] 7
--END-- --END--
"""); """)
# In Reuben's report this first block built an incorrect deterministic # In Reuben's report this first block built an incorrect deterministic
# automaton, which ultimately led to an non-empty product. The second # automaton, which ultimately led to an non-empty product. The second
@ -82,10 +82,10 @@ print("use_simulation=True")
b1 = spot.tgba_determinize(b, False, True, True, True) b1 = spot.tgba_determinize(b, False, True, True, True)
assert b1.num_states() == 5 assert b1.num_states() == 5
b1 = spot.remove_fin(spot.dualize(b1)) b1 = spot.remove_fin(spot.dualize(b1))
assert not a.intersects(b1); assert not a.intersects(b1)
print("\nuse_simulation=False") print("\nuse_simulation=False")
b2 = spot.tgba_determinize(b, False, True, False, True) b2 = spot.tgba_determinize(b, False, True, False, True)
assert b2.num_states() == 5 assert b2.num_states() == 5
b2 = spot.remove_fin(spot.dualize(b2)) b2 = spot.remove_fin(spot.dualize(b2))
assert not a.intersects(b2); assert not a.intersects(b2)

View file

@ -21,68 +21,78 @@
import spot import spot
import buddy import buddy
match_strings = [('is_buchi', 'is_co_buchi'),\ match_strings = [('is_buchi', 'is_co_buchi'),
('is_generalized_buchi', 'is_generalized_co_buchi'),\ ('is_generalized_buchi', 'is_generalized_co_buchi'),
('is_all', 'is_none'),\ ('is_all', 'is_none'),
('is_all', 'is_all'), ('is_all', 'is_all'),
('is_buchi', 'is_all')] ('is_buchi', 'is_all')]
# existential and universal are dual # existential and universal are dual
# deterministic is self-dual # deterministic is self-dual
def dualtype(aut, dual): def dualtype(aut, dual):
if dual.acc().is_none(): return True if dual.acc().is_none():
return (not spot.is_deterministic(aut) or spot.is_deterministic(dual))\ return True
and (spot.is_universal(dual) or not aut.is_existential())\ return (not spot.is_deterministic(aut) or spot.is_deterministic(dual))\
and (dual.is_existential() or not spot.is_universal(aut)) and (spot.is_universal(dual) or not aut.is_existential())\
and (dual.is_existential() or not spot.is_universal(aut))
def produce_phi(rg, n): def produce_phi(rg, n):
phi = [] phi = []
while len(phi) < n: while len(phi) < n:
phi.append(rg.next()) phi.append(rg.next())
return phi return phi
def produce_automaton(phi): def produce_automaton(phi):
aut = [] aut = []
for f in phi: for f in phi:
aut.append(spot.translate(f)) aut.append(spot.translate(f))
return aut return aut
def test_aut(aut, d = None):
if d is None:
d = spot.dualize(aut)
aa = aut.acc()
da = d.acc()
complete = spot.is_complete(aut) def test_aut(aut, d=None):
univ = aut.is_univ_dest(aut.get_init_state_number()) if d is None:
an = aut.num_states() d = spot.dualize(aut)
dn = d.num_states() aa = aut.acc()
da = d.acc()
if not dualtype(aut, d): complete = spot.is_complete(aut)
return (False, 'Incorrect transition mode resulting of dual') univ = aut.is_univ_dest(aut.get_init_state_number())
for p in match_strings: an = aut.num_states()
if ((getattr(aa, p[0])() and getattr(da, p[1])())\ dn = d.num_states()
or (getattr(aa, p[1])() and getattr(da, p[0])())):
return (True, '') if not dualtype(aut, d):
return (False, 'Incorrect acceptance type dual') return (False, 'Incorrect transition mode resulting of dual')
for p in match_strings:
if ((getattr(aa, p[0])() and getattr(da, p[1])())
or (getattr(aa, p[1])() and getattr(da, p[0])())):
return (True, '')
return (False, 'Incorrect acceptance type dual')
# Tests that a (deterministic) automaton and its complement have complementary # Tests that a (deterministic) automaton and its complement have complementary
# languages. # languages.
# FIXME This test could be extended to non-deterministic automata with a # FIXME This test could be extended to non-deterministic automata with a
# dealternization procedure. # dealternization procedure.
def test_complement(aut): def test_complement(aut):
assert aut.is_deterministic() assert aut.is_deterministic()
d = spot.dualize(aut) d = spot.dualize(aut)
s = spot.product_or(aut, d) s = spot.product_or(aut, d)
assert spot.dualize(s).is_empty() assert spot.dualize(s).is_empty()
def test_assert(a, d=None): def test_assert(a, d=None):
t = test_aut(a, d) t = test_aut(a, d)
if not t[0]: if not t[0]:
print (t[1]) print (t[1])
print (a.to_str('hoa')) print (a.to_str('hoa'))
print (spot.dualize(a).to_str('hoa')) print (spot.dualize(a).to_str('hoa'))
assert False assert False
aut = spot.translate('a') aut = spot.translate('a')
@ -591,8 +601,8 @@ spot.srand(0)
rg = spot.randltlgenerator(2, opts) rg = spot.randltlgenerator(2, opts)
for a in produce_automaton(produce_phi(rg, 1000)): for a in produce_automaton(produce_phi(rg, 1000)):
test_assert(a) test_assert(a)
test_assert(spot.dualize(a), spot.dualize(spot.dualize(a))) test_assert(spot.dualize(a), spot.dualize(spot.dualize(a)))
aut = spot.automaton(""" aut = spot.automaton("""
HOA: v1 HOA: v1
@ -606,4 +616,4 @@ State: 0
test_complement(aut) test_complement(aut)
for a in spot.automata('randaut -A \"random 0..6\" -H -D -n50 4|'): for a in spot.automata('randaut -A \"random 0..6\" -H -D -n50 4|'):
test_complement(a) test_complement(a)

View file

@ -25,6 +25,7 @@
import spot import spot
import buddy import buddy
def report_missing_exception(): def report_missing_exception():
raise RuntimeError("missing exception") raise RuntimeError("missing exception")
@ -147,7 +148,7 @@ else:
report_missing_exception() report_missing_exception()
try: try:
m = spot.mark_t([0,n,1]) m = spot.mark_t([0, n, 1])
except RuntimeError as e: except RuntimeError as e:
assert "bit index is out of bounds" in str(e) assert "bit index is out of bounds" in str(e)
else: else:

View file

@ -71,8 +71,8 @@ else:
try: try:
gen.ltl_pattern(gen.LTL_OR_G, -10) gen.ltl_pattern(gen.LTL_OR_G, -10)
except RuntimeError as e: except RuntimeError as e:
assert 'or-g' in str(e) assert 'or-g' in str(e)
assert 'positive' in str(e) assert 'positive' in str(e)
else: else:
exit(2) exit(2)

View file

@ -139,8 +139,6 @@ State: 1 [0&1] 0 {4 6 7} [0&!1] 1 {3 6} [!0&1] 0 {4 7} [!0&!1] 1 {0}
--END--""") --END--""")
def generic_emptiness2_rec(aut): def generic_emptiness2_rec(aut):
spot.cleanup_acceptance_here(aut, False) spot.cleanup_acceptance_here(aut, False)
# Catching 'false' acceptance here is an optimization that could be removed. # Catching 'false' acceptance here is an optimization that could be removed.
@ -183,6 +181,8 @@ def generic_emptiness2_rec(aut):
return True return True
# A very old python version of spot.generic_emptiness_check() # A very old python version of spot.generic_emptiness_check()
def generic_emptiness2(aut): def generic_emptiness2(aut):
old_a = spot.acc_cond(aut.acc()) old_a = spot.acc_cond(aut.acc())
res = generic_emptiness2_rec(aut) res = generic_emptiness2_rec(aut)
@ -191,6 +191,8 @@ def generic_emptiness2(aut):
return res return res
# A more modern python version of spot.generic_emptiness_check() # A more modern python version of spot.generic_emptiness_check()
def is_empty1(g): def is_empty1(g):
si = spot.scc_info_with_options(g, spot.scc_info_options_NONE) si = spot.scc_info_with_options(g, spot.scc_info_options_NONE)
for scc_num in range(si.scc_count()): for scc_num in range(si.scc_count()):
@ -200,17 +202,21 @@ def is_empty1(g):
return False return False
return True return True
def is_scc_empty1(si, scc_num, acc=None): def is_scc_empty1(si, scc_num, acc=None):
if acc is None: # acceptance isn't forced, get it from the automaton if acc is None: # acceptance isn't forced, get it from the automaton
acc = si.get_aut().acc() acc = si.get_aut().acc()
occur, common = si.acc_sets_of(scc_num), si.common_sets_of(scc_num) occur, common = si.acc_sets_of(scc_num), si.common_sets_of(scc_num)
acc = acc.restrict_to(occur) acc = acc.restrict_to(occur)
acc = acc.remove(common, False) acc = acc.remove(common, False)
if acc.is_t(): return False if acc.is_t():
if acc.is_f(): return True return False
if acc.accepting(occur): return False if acc.is_f():
return True
if acc.accepting(occur):
return False
for cl in acc.top_disjuncts(): for cl in acc.top_disjuncts():
fu = cl.fin_unit() # Is there Fin at the top level fu = cl.fin_unit() # Is there Fin at the top level
if fu: if fu:
with spot.scc_and_mark_filter(si, scc_num, fu) as filt: with spot.scc_and_mark_filter(si, scc_num, fu) as filt:
filt.override_acceptance(cl.remove(fu, True)) filt.override_acceptance(cl.remove(fu, True))
@ -229,22 +235,25 @@ def is_scc_empty1(si, scc_num, acc=None):
return False return False
return True return True
def is_empty2(g): def is_empty2(g):
return is_empty2_rec(spot.scc_and_mark_filter(g, g.acc().fin_unit())) return is_empty2_rec(spot.scc_and_mark_filter(g, g.acc().fin_unit()))
def is_empty2_rec(g): def is_empty2_rec(g):
si = spot.scc_info_with_options(g, spot.scc_info_options_STOP_ON_ACC) si = spot.scc_info_with_options(g, spot.scc_info_options_STOP_ON_ACC)
if si.one_accepting_scc() >= 0: if si.one_accepting_scc() >= 0:
return False return False
for scc_num in range(si.scc_count()): for scc_num in range(si.scc_count()):
if si.is_rejecting_scc(scc_num): # this includes trivial SCCs if si.is_rejecting_scc(scc_num): # this includes trivial SCCs
continue continue
if not is_scc_empty2(si, scc_num): if not is_scc_empty2(si, scc_num):
return False return False
return True return True
def is_scc_empty2(si, scc_num, acc=None): def is_scc_empty2(si, scc_num, acc=None):
if acc is None: # acceptance isn't forced, get it from the automaton if acc is None: # acceptance isn't forced, get it from the automaton
acc = si.get_aut().acc() acc = si.get_aut().acc()
occur, common = si.acc_sets_of(scc_num), si.common_sets_of(scc_num) occur, common = si.acc_sets_of(scc_num), si.common_sets_of(scc_num)
acc = acc.restrict_to(occur) acc = acc.restrict_to(occur)
@ -252,7 +261,7 @@ def is_scc_empty2(si, scc_num, acc=None):
# 3 stop conditions removed here, because they are caught by # 3 stop conditions removed here, because they are caught by
# one_accepting_scc() or is_rejecting_scc() in is_empty2_rec() # one_accepting_scc() or is_rejecting_scc() in is_empty2_rec()
for cl in acc.top_disjuncts(): for cl in acc.top_disjuncts():
fu = cl.fin_unit() # Is there Fin at the top level fu = cl.fin_unit() # Is there Fin at the top level
if fu: if fu:
with spot.scc_and_mark_filter(si, scc_num, fu) as filt: with spot.scc_and_mark_filter(si, scc_num, fu) as filt:
filt.override_acceptance(cl.remove(fu, True)) filt.override_acceptance(cl.remove(fu, True))
@ -271,6 +280,7 @@ def is_scc_empty2(si, scc_num, acc=None):
return False return False
return True return True
def run_bench(automata): def run_bench(automata):
for aut in automata: for aut in automata:
# Make sure our three implementation behave identically # Make sure our three implementation behave identically
@ -287,4 +297,5 @@ def run_bench(automata):
run3 = spot.generic_accepting_run(aut) run3 = spot.generic_accepting_run(aut)
assert run3.replay(spot.get_cout()) is True assert run3.replay(spot.get_cout()) is True
run_bench([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a11, a360]) run_bench([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a11, a360])

View file

@ -25,37 +25,37 @@ bdd_setvarnum(5)
V = [bdd_ithvar(i) for i in range(5)] V = [bdd_ithvar(i) for i in range(5)]
a = V[0] & V[1] & -V[2] a = V[0] & V[1] & -V[2]
b = 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] c = -V[0] & V[1] & -V[2] & -V[3]
d = V[1] & -V[2] d = V[1] & -V[2]
e = V[1] & V[2] & -V[3] & V[4] e = V[1] & V[2] & -V[3] & V[4]
f = V[0] & -V[3] & V[4] f = V[0] & -V[3] & V[4]
g = -V[0] | V[1] g = -V[0] | V[1]
assert(bdd_implies(b,a)) assert(bdd_implies(b, a))
assert(not bdd_implies(a,b)) assert(not bdd_implies(a, b))
assert(not bdd_implies(c,a)) assert(not bdd_implies(c, a))
assert(bdd_implies(a,d)) assert(bdd_implies(a, d))
assert(bdd_implies(b,d)) assert(bdd_implies(b, d))
assert(bdd_implies(c,d)) assert(bdd_implies(c, d))
assert(bdd_implies(d,d)) assert(bdd_implies(d, d))
assert(not bdd_implies(e,d)) assert(not bdd_implies(e, d))
assert(not bdd_implies(d,e)) assert(not bdd_implies(d, e))
assert(not bdd_implies(f,e)) assert(not bdd_implies(f, e))
assert(not bdd_implies(e,f)) assert(not bdd_implies(e, f))
assert(bdd_implies(bddfalse,f)) assert(bdd_implies(bddfalse, f))
assert(not bdd_implies(bddtrue,f)) assert(not bdd_implies(bddtrue, f))
assert(bdd_implies(f,bddtrue)) assert(bdd_implies(f, bddtrue))
assert(not bdd_implies(f,bddfalse)) assert(not bdd_implies(f, bddfalse))
assert(bdd_implies(a,g)) assert(bdd_implies(a, g))
a = (-V[2] & (-V[1] | V[0])) | (-V[0] & V[1] & V[2]) a = (-V[2] & (-V[1] | V[0])) | (-V[0] & V[1] & V[2])
b = V[1] | -V[2] b = V[1] | -V[2]
assert(bdd_implies(a,b)) assert(bdd_implies(a, b))
# Cleanup all BDD variables before calling bdd_done(), otherwise # Cleanup all BDD variables before calling bdd_done(), otherwise
# bdd_delref will be called after bdd_done() and this is unsafe in # bdd_delref will be called after bdd_done() and this is unsafe in
# optimized builds. # optimized builds.
V = a = b = c = d = e = f = g = 0; V = a = b = c = d = e = f = g = 0
bdd_done() bdd_done()

View file

@ -34,7 +34,8 @@ d = simp.get_dict()
a = spot.ltl_to_tgba_fm(pf.f, d) a = spot.ltl_to_tgba_fm(pf.f, d)
g = spot.parse_infix_boolean('b&c', e) g = spot.parse_infix_boolean('b&c', e)
b = simp.as_bdd(g.f) b = simp.as_bdd(g.f)
buddy.bdd_printset(b); spot.nl_cout() buddy.bdd_printset(b)
spot.nl_cout()
del g del g
s0 = a.get_init_state() s0 = a.get_init_state()
@ -43,11 +44,13 @@ it.first()
while not it.done(): while not it.done():
c = it.cond() c = it.cond()
sys.stdout.write("%s\n" % c) sys.stdout.write("%s\n" % c)
b &= c # `&=' is defined only in buddy. So if this statement works b &= c # `&=' is defined only in buddy. So if this statement works
# it means buddy can grok spot's objects. # it means buddy can grok spot's objects.
buddy.bdd_printset(c); spot.nl_cout() buddy.bdd_printset(c)
spot.nl_cout()
it.next() it.next()
buddy.bdd_printset(b); spot.nl_cout() buddy.bdd_printset(b)
spot.nl_cout()
sys.stdout.write("%s\n" % b) sys.stdout.write("%s\n" % b)
del it del it
del s0 del s0

View file

@ -12,7 +12,9 @@ with those stored in the notebook.
from __future__ import print_function from __future__ import print_function
import os,sys,time import os
import sys
import time
import base64 import base64
import re import re
import pprint import pprint
@ -40,7 +42,7 @@ except ImportError:
except ImportError: except ImportError:
try: try:
from IPython.zmq.blockingkernelmanager \ from IPython.zmq.blockingkernelmanager \
import BlockingKernelManager as KernelManager import BlockingKernelManager as KernelManager
except: except:
print('IPython is needed to run this script.') print('IPython is needed to run this script.')
sys.exit(77) sys.exit(77)
@ -51,6 +53,7 @@ try:
except ImportError: except ImportError:
from IPython.nbformat import v4 as nbformat from IPython.nbformat import v4 as nbformat
def compare_png(a64, b64): def compare_png(a64, b64):
"""compare two b64 PNGs (incomplete)""" """compare two b64 PNGs (incomplete)"""
try: try:
@ -61,6 +64,7 @@ def compare_png(a64, b64):
bdata = base64.decodestring(b64) bdata = base64.decodestring(b64)
return True return True
def canonicalize(s, type, ignores): def canonicalize(s, type, ignores):
"""sanitize a string for comparison. """sanitize a string for comparison.
@ -163,8 +167,8 @@ def canonical_dict(dict, ignores):
if 'ename' in dict and dict['ename'] == 'CalledProcessError': if 'ename' in dict and dict['ename'] == 'CalledProcessError':
# CalledProcessError message has a final dot in Python 3.6 # CalledProcessError message has a final dot in Python 3.6
dict['evalue'] = \ dict['evalue'] = \
re.sub(r"(' returned non-zero exit status \d+)\.", r'\1', re.sub(r"(' returned non-zero exit status \d+)\.", r'\1',
dict['evalue']) dict['evalue'])
if 'transient' in dict: if 'transient' in dict:
del dict['transient'] del dict['transient']
@ -195,6 +199,7 @@ def compare_outputs(ref, test, ignores=[]):
fromfile='expected', tofile='effective'))) fromfile='expected', tofile='effective')))
return False return False
def _wait_for_ready_backport(kc): def _wait_for_ready_backport(kc):
"""Backport BlockingKernelClient.wait_for_ready from IPython 3""" """Backport BlockingKernelClient.wait_for_ready from IPython 3"""
# Wait for kernel info reply on shell channel # Wait for kernel info reply on shell channel
@ -210,6 +215,7 @@ def _wait_for_ready_backport(kc):
except Empty: except Empty:
break break
def run_cell(kc, cell): def run_cell(kc, cell):
kc.execute(cell.source) kc.execute(cell.source)
# wait for finish, maximum 30s # wait for finish, maximum 30s
@ -295,7 +301,6 @@ def test_notebook(ipynb):
print("OK") print("OK")
successes += 1 successes += 1
print("tested notebook %s" % ipynb) print("tested notebook %s" % ipynb)
print(" %3i cells successfully replicated" % successes) print(" %3i cells successfully replicated" % successes)
if failures: if failures:
@ -308,6 +313,7 @@ def test_notebook(ipynb):
if failures | errors: if failures | errors:
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
for ipynb in sys.argv[1:]: for ipynb in sys.argv[1:]:
print("testing %s" % ipynb) print("testing %s" % ipynb)

View file

@ -36,7 +36,7 @@ k.new_edge(s3, s3)
k.new_edge(s3, s2) k.new_edge(s3, s2)
k.set_init_state(s1) k.set_init_state(s1)
hoa="""HOA: v1 hoa = """HOA: v1
States: 3 States: 3
Start: 0 Start: 0
AP: 2 "p1" "p2" AP: 2 "p1" "p2"

View file

@ -28,6 +28,7 @@ import sys
import getopt import getopt
import spot import spot
def usage(prog): def usage(prog):
sys.stderr.write("""Usage: %s [OPTIONS...] formula sys.stderr.write("""Usage: %s [OPTIONS...] formula

View file

@ -30,7 +30,7 @@ formulas = ['GFa', 'FGa', '(GFa) U b',
'(a M b) W c', 'a W (b M c)', '(a M b) W c', 'a W (b M c)',
'(a U b) R c', 'a R (b U c)', '(a U b) R c', 'a R (b U c)',
'(a W b) M c', 'a M (b W c)', '(a W b) M c', 'a M (b W c)',
] ]
# The rewriting assume the atomic proposition will not change # The rewriting assume the atomic proposition will not change
# once we reache the non-alive part. # once we reache the non-alive part.

View file

@ -44,8 +44,8 @@ for str1, isl in l:
assert isl == pf.f.is_leaf() assert isl == pf.f.is_leaf()
del pf del pf
assert spot.formula('a').is_leaf(); assert spot.formula('a').is_leaf()
assert spot.formula('0').is_leaf(); assert spot.formula('0').is_leaf()
for str1 in ['a * b', 'a xor b', 'a <-> b']: for str1 in ['a * b', 'a xor b', 'a <-> b']:
pf = spot.parse_infix_boolean(str1, e, False) pf = spot.parse_infix_boolean(str1, e, False)
@ -84,70 +84,71 @@ assert f6.errors
del f6 del f6
for (x, msg) in [('{foo[->bug]}', "treating this goto block as [->]"), for (x, msg) in [('{foo[->bug]}', "treating this goto block as [->]"),
('{foo[->', 'missing closing bracket for goto operator'), ('{foo[->', 'missing closing bracket for goto operator'),
('{foo[->3..1]}', "reversed range"), ('{foo[->3..1]}', "reversed range"),
('{foo[*bug]}', "treating this star block as [*]"), ('{foo[*bug]}', "treating this star block as [*]"),
('{foo[*bug', "missing closing bracket for star"), ('{foo[*bug', "missing closing bracket for star"),
('{foo[*3..1]}', "reversed range"), ('{foo[*3..1]}', "reversed range"),
('{[*3..1]}', "reversed range"), ('{[*3..1]}', "reversed range"),
('{foo[:*bug]}', "treating this fusion-star block as [:*]"), ('{foo[:*bug]}', "treating this fusion-star block as [:*]"),
('{foo[:*3..1]}', "reversed range"), ('{foo[:*3..1]}', "reversed range"),
('{foo[:*bug', "missing closing bracket for fusion-star"), ('{foo[:*bug', "missing closing bracket for fusion-star"),
('{foo[=bug]}', "treating this equal block as [=]"), ('{foo[=bug]}', "treating this equal block as [=]"),
('{foo[=bug', "missing closing bracket for equal operator"), ('{foo[=bug', "missing closing bracket for equal operator"),
('{foo[=3..1]}', "reversed range"), ('{foo[=3..1]}', "reversed range"),
('{()}', "treating this brace block as false"), ('{()}', "treating this brace block as false"),
('{(a b)}', "treating this parenthetical block as false"), ('{(a b)}', "treating this parenthetical block as false"),
('{(a*}', "missing closing parenthesis"), ('{(a*}', "missing closing parenthesis"),
('{(a*&)}', "missing right operand for " ('{(a*&)}', "missing right operand for "
+ "\"non-length-matching and operator\""), + "\"non-length-matching and operator\""),
('{(a*&&)}', "missing right operand for " ('{(a*&&)}', "missing right operand for "
+ "\"length-matching and operator\""), + "\"length-matching and operator\""),
('{(a*|)}', "missing right operand for \"or operator\""), ('{(a*|)}', "missing right operand for \"or operator\""),
('{a*;}', "missing right operand for \"concat operator\""), ('{a*;}', "missing right operand for \"concat operator\""),
('{a*::b}', "missing right operand for \"fusion operator\""), ('{a*::b}', "missing right operand for \"fusion operator\""),
('{a* xor }', "missing right operand for \"xor operator\""), ('{a* xor }', "missing right operand for \"xor operator\""),
('{a* -> }', "missing right operand for " ('{a* -> }', "missing right operand for "
+ "\"implication operator\""), + "\"implication operator\""),
('{a <-> <-> b }', ('{a <-> <-> b }',
"missing right operand for \"equivalent operator\""), "missing right operand for \"equivalent operator\""),
('{a;b b}', "ignoring this"), ('{a;b b}', "ignoring this"),
('{*', "missing closing brace"), ('{*', "missing closing brace"),
('{(a', "missing closing parenthesis"), ('{(a', "missing closing parenthesis"),
('{* a', "ignoring trailing garbage and missing closing brace"), ('{* a',
('F(a b)', "ignoring this"), "ignoring trailing garbage and missing closing brace"),
('F(-)', "treating this parenthetical block as false"), ('F(a b)', "ignoring this"),
('F(', "missing closing parenthesis"), ('F(-)', "treating this parenthetical block as false"),
('F(a b', "ignoring trailing garbage and " ('F(', "missing closing parenthesis"),
+ "missing closing parenthesis"), ('F(a b', "ignoring trailing garbage and "
('F(-', "missing closing parenthesis"), + "missing closing parenthesis"),
('F(-', "parenthetical block as false"), ('F(-', "missing closing parenthesis"),
('a&', "missing right operand for \"and operator\""), ('F(-', "parenthetical block as false"),
('a*', "missing right operand for \"and operator\""), ('a&', "missing right operand for \"and operator\""),
('a|', "missing right operand for \"or operator\""), ('a*', "missing right operand for \"and operator\""),
('a^', "missing right operand for \"xor operator\""), ('a|', "missing right operand for \"or operator\""),
('a->', "missing right operand for \"implication operator\""), ('a^', "missing right operand for \"xor operator\""),
('a<->', "missing right operand for \"equivalent operator\""), ('a->', "missing right operand for \"implication operator\""),
('!', "missing right operand for \"not operator\""), ('a<->', "missing right operand for \"equivalent operator\""),
('a W', "missing right operand for \"weak until operator\""), ('!', "missing right operand for \"not operator\""),
('a U', "missing right operand for \"until operator\""), ('a W', "missing right operand for \"weak until operator\""),
('a R', "missing right operand for \"release operator\""), ('a U', "missing right operand for \"until operator\""),
('a M', "missing right operand for " ('a R', "missing right operand for \"release operator\""),
+ "\"strong release operator\""), ('a M', "missing right operand for "
('{a}[]->', "missing right operand for " + "\"strong release operator\""),
+ "\"universal overlapping concat operator\""), ('{a}[]->', "missing right operand for "
('{a}[]=>', "missing right operand for " + "\"universal overlapping concat operator\""),
+ "\"universal non-overlapping concat operator\""), ('{a}[]=>', "missing right operand for "
('{a}<>->', "missing right operand for " + "\"universal non-overlapping concat operator\""),
+ "\"existential overlapping concat operator\""), ('{a}<>->', "missing right operand for "
('{a}<>=>', "missing right operand for " + "\"existential overlapping concat operator\""),
+ "\"existential non-overlapping concat operator\""), ('{a}<>=>', "missing right operand for "
('(X)', "missing right operand for \"next operator\""), + "\"existential non-overlapping concat operator\""),
('("X)', "unclosed string"), ('(X)', "missing right operand for \"next operator\""),
('("X)', "missing closing parenthesis"), ('("X)', "unclosed string"),
('{"X', "unclosed string"), ('("X)', "missing closing parenthesis"),
('{"X}', "missing closing brace"), ('{"X', "unclosed string"),
]: ('{"X}', "missing closing brace"),
]:
f7 = spot.parse_infix_psl(x) f7 = spot.parse_infix_psl(x)
assert f7.errors assert f7.errors
ostr = spot.ostringstream() ostr = spot.ostringstream()
@ -158,20 +159,20 @@ for (x, msg) in [('{foo[->bug]}', "treating this goto block as [->]"),
del f7 del f7
for (x, msg) in [('a&', "missing right operand for \"and operator\""), for (x, msg) in [('a&', "missing right operand for \"and operator\""),
('a*', "missing right operand for \"and operator\""), ('a*', "missing right operand for \"and operator\""),
('a|', "missing right operand for \"or operator\""), ('a|', "missing right operand for \"or operator\""),
('a^', "missing right operand for \"xor operator\""), ('a^', "missing right operand for \"xor operator\""),
('a->', "missing right operand for \"implication operator\""), ('a->', "missing right operand for \"implication operator\""),
('a<->', "missing right operand for \"equivalent operator\""), ('a<->', "missing right operand for \"equivalent operator\""),
('(-', "parenthetical block as false"), ('(-', "parenthetical block as false"),
('(-', "missing closing parenthesis"), ('(-', "missing closing parenthesis"),
('(-)', "treating this parenthetical block as false"), ('(-)', "treating this parenthetical block as false"),
('(a', "missing closing parenthesis"), ('(a', "missing closing parenthesis"),
('(a b)', "ignoring this"), ('(a b)', "ignoring this"),
('(a b', "ignoring trailing garbage and " ('(a b', "ignoring trailing garbage and "
+ "missing closing parenthesis"), + "missing closing parenthesis"),
('!', "missing right operand for \"not operator\""), ('!', "missing right operand for \"not operator\""),
]: ]:
f8 = spot.parse_infix_boolean(x) f8 = spot.parse_infix_boolean(x)
assert f8.errors assert f8.errors
ostr = spot.ostringstream() ostr = spot.ostringstream()
@ -182,12 +183,12 @@ for (x, msg) in [('a&', "missing right operand for \"and operator\""),
del f8 del f8
for (x, msg) in [('a->', "missing right operand for \"implication operator\""), for (x, msg) in [('a->', "missing right operand for \"implication operator\""),
('a<->', "missing right operand for \"equivalent operator\""), ('a<->', "missing right operand for \"equivalent operator\""),
('(aa', "missing closing parenthesis"), ('(aa', "missing closing parenthesis"),
('("aa', "missing closing parenthesis"), ('("aa', "missing closing parenthesis"),
('"(aa', "unclosed string"), ('"(aa', "unclosed string"),
('{aa', "missing closing brace"), ('{aa', "missing closing brace"),
]: ]:
f9 = spot.parse_infix_psl(x, spot.default_environment.instance(), f9 = spot.parse_infix_psl(x, spot.default_environment.instance(),
False, True) False, True)
assert f9.errors assert f9.errors

View file

@ -23,7 +23,7 @@
import spot import spot
import sys import sys
#---------------------------------------------------------------------- # ----------------------------------------------------------------------
a = spot.formula.ap('a') a = spot.formula.ap('a')
b = spot.formula.ap('b') b = spot.formula.ap('b')
c = spot.formula.ap('c') c = spot.formula.ap('c')
@ -31,7 +31,7 @@ c2 = spot.formula.ap('c')
assert c == c2 assert c == c2
op = spot.formula.And([a, b]) op = spot.formula.And([a, b])
op2 = spot.formula.And([op, c]) op2 = spot.formula.And([op, c])
op3 = spot.formula.And([a, c, b]) op3 = spot.formula.And([a, c, b])
@ -55,7 +55,7 @@ assert op4 == op2
del op2, op3, op4 del op2, op3, op4
#---------------------------------------------------------------------- # ----------------------------------------------------------------------
a = spot.formula.ap('a') a = spot.formula.ap('a')
b = spot.formula.ap('b') b = spot.formula.ap('b')
c = spot.formula.ap('c') c = spot.formula.ap('c')
@ -65,14 +65,15 @@ F = spot.formula.ff()
f1 = spot.formula.Equiv(c, a) f1 = spot.formula.Equiv(c, a)
f2 = spot.formula.Implies(a, b) f2 = spot.formula.Implies(a, b)
f3 = spot.formula.Xor(b, c) f3 = spot.formula.Xor(b, c)
f4 = spot.formula.Not(f3); del f3 f4 = spot.formula.Not(f3)
del f3
f5 = spot.formula.Xor(F, c) f5 = spot.formula.Xor(F, c)
del a, b, c, T, F, f1, f2, f4, f5 del a, b, c, T, F, f1, f2, f4, f5
assert spot.fnode_instances_check() assert spot.fnode_instances_check()
#---------------------------------------------------------------------- # ----------------------------------------------------------------------
assert str([str(x) for x in spot.formula('a &b & c')]) == "['a', 'b', 'c']" assert str([str(x) for x in spot.formula('a &b & c')]) == "['a', 'b', 'c']"
@ -83,18 +84,23 @@ def switch_g_f(x):
return spot.formula.G(switch_g_f(x[0])) return spot.formula.G(switch_g_f(x[0]))
return x.map(switch_g_f) return x.map(switch_g_f)
f = spot.formula('GFa & XFGb & Fc & G(a | b | Fd)') f = spot.formula('GFa & XFGb & Fc & G(a | b | Fd)')
assert str(switch_g_f(f)) == 'FGa & XGFb & Gc & F(a | b | Gd)' assert str(switch_g_f(f)) == 'FGa & XGFb & Gc & F(a | b | Gd)'
x = 0 x = 0
def count_g(f): def count_g(f):
global x global x
if f._is(spot.op_G): if f._is(spot.op_G):
x += 1 x += 1
f.traverse(count_g) f.traverse(count_g)
assert x == 3 assert x == 3
#---------------------------------------------------------------------- # ----------------------------------------------------------------------
# The example from tut01.org # The example from tut01.org
@ -106,7 +112,7 @@ Spin syntax: {f:s}
Default for shell: echo {f:q} | ... Default for shell: echo {f:q} | ...
LBT for shell: echo {f:lq} | ... LBT for shell: echo {f:lq} | ...
Default for CSV: ...,{f:c},... Default for CSV: ...,{f:c},...
Wring, centered: {f:w:~^50}""".format(f = formula) Wring, centered: {f:w:~^50}""".format(f=formula)
assert res == """\ assert res == """\
Default output: a U (b U "$strange[0]=name") Default output: a U (b U "$strange[0]=name")
@ -135,10 +141,13 @@ for (input, output) in [('(a&b)<->b', 'b->(a&b)'),
assert(f == output) assert(f == output)
assert(spot.are_equivalent(input, output)) assert(spot.are_equivalent(input, output))
def myparse(input): def myparse(input):
env = spot.default_environment.instance() env = spot.default_environment.instance()
pf = spot.parse_infix_psl(input, env) pf = spot.parse_infix_psl(input, env)
return pf.f return pf.f
# This used to fail, because myparse would return a pointer # This used to fail, because myparse would return a pointer
# to pf.f inside the destroyed pf. # to pf.f inside the destroyed pf.
assert myparse('a U b') == spot.formula('a U b') assert myparse('a U b') == spot.formula('a U b')

View file

@ -37,7 +37,7 @@ assert h == f
autg = g.translate() autg = g.translate()
spot.relabel_here(autg, m) spot.relabel_here(autg, m)
assert str(autg.ap()) == \ assert str(autg.ap()) == \
'(spot.formula("a"), spot.formula("b"), spot.formula("c"))' '(spot.formula("a"), spot.formula("b"), spot.formula("c"))'
assert spot.isomorphism_checker.are_isomorphic(autg, f.translate()) assert spot.isomorphism_checker.are_isomorphic(autg, f.translate())
a = spot.formula('a') a = spot.formula('a')

View file

@ -27,32 +27,39 @@ m2 = spot.mark_t([2])
m3 = spot.mark_t([3]) m3 = spot.mark_t([3])
mall = spot.mark_t() mall = spot.mark_t()
def test_rs(acc, rs, expected_res, expected_pairs): def test_rs(acc, rs, expected_res, expected_pairs):
res, p = getattr(acc, 'is_' + rs + '_like')() res, p = getattr(acc, 'is_' + rs + '_like')()
assert res == expected_res assert res == expected_res
if expected_res: if expected_res:
expected_pairs.sort() expected_pairs.sort()
p = sorted(p) p = sorted(p)
for a,b in zip (p, expected_pairs): for a, b in zip(p, expected_pairs):
assert a.fin == b.fin and a.inf == b.inf assert a.fin == b.fin and a.inf == b.inf
def switch_pairs(pairs): def switch_pairs(pairs):
if pairs == None: if pairs == None:
return None return None
r = [] r = []
for p in pairs: for p in pairs:
r.append(spot.rs_pair(p.inf, p.fin)) r.append(spot.rs_pair(p.inf, p.fin))
return r return r
def test_streett(acc, expected_streett_like, expected_pairs): def test_streett(acc, expected_streett_like, expected_pairs):
test_rs(acc, 'streett', expected_streett_like, expected_pairs) test_rs(acc, 'streett', expected_streett_like, expected_pairs)
o_acc = spot.acc_cond(acc.get_acceptance().complement()) o_acc = spot.acc_cond(acc.get_acceptance().complement())
test_rs(o_acc, 'rabin', expected_streett_like, switch_pairs(expected_pairs)) test_rs(o_acc, 'rabin', expected_streett_like,
switch_pairs(expected_pairs))
def test_rabin(acc, expected_rabin_like, expected_pairs): def test_rabin(acc, expected_rabin_like, expected_pairs):
test_rs(acc, 'rabin', expected_rabin_like, expected_pairs) test_rs(acc, 'rabin', expected_rabin_like, expected_pairs)
o_acc = spot.acc_cond(acc.get_acceptance().complement()) o_acc = spot.acc_cond(acc.get_acceptance().complement())
test_rs(o_acc, 'streett', expected_rabin_like, switch_pairs(expected_pairs)) test_rs(o_acc, 'streett', expected_rabin_like,
switch_pairs(expected_pairs))
acc = spot.acc_cond(spot.acc_code('Fin(0)')) acc = spot.acc_cond(spot.acc_code('Fin(0)'))
test_streett(acc, True, [spot.rs_pair(m0, mall)]) test_streett(acc, True, [spot.rs_pair(m0, mall)])
@ -75,12 +82,12 @@ test_streett(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m0, m2)])
acc = spot.acc_cond(spot.acc_code('(Fin(0)|Inf(1))&(Fin(1)|Inf(2))')) acc = spot.acc_cond(spot.acc_code('(Fin(0)|Inf(1))&(Fin(1)|Inf(2))'))
test_streett(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2)]) test_streett(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2)])
acc = spot.acc_cond(spot.acc_code('(Fin(0)|Inf(1))&(Fin(1)|Inf(2))'\ acc = spot.acc_cond(spot.acc_code('(Fin(0)|Inf(1))&(Fin(1)|Inf(2))'
'&(Fin(3)&Inf(3))')) '&(Fin(3)&Inf(3))'))
test_streett(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2),\ test_streett(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2),
spot.rs_pair(m3, mall), spot.rs_pair(mall, m3)]) spot.rs_pair(m3, mall), spot.rs_pair(mall, m3)])
acc = spot.acc_cond(spot.acc_code('(Fin(0)|Inf(1))&(Fin(1)|Inf(2))'\ acc = spot.acc_cond(spot.acc_code('(Fin(0)|Inf(1))&(Fin(1)|Inf(2))'
'&(Fin(3)&Inf(3))&(Fin(4)|Inf(5)|Inf(6))')) '&(Fin(3)&Inf(3))&(Fin(4)|Inf(5)|Inf(6))'))
test_streett(acc, False, None) test_streett(acc, False, None)
@ -102,13 +109,11 @@ test_rabin(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m0, m2)])
acc = spot.acc_cond(spot.acc_code('(Fin(0)&Inf(1))|(Fin(1)&Inf(2))')) acc = spot.acc_cond(spot.acc_code('(Fin(0)&Inf(1))|(Fin(1)&Inf(2))'))
test_rabin(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2)]) test_rabin(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2)])
acc = spot.acc_cond(spot.acc_code('(Fin(0)&Inf(1))|(Fin(1)&Inf(2))'\ acc = spot.acc_cond(spot.acc_code('(Fin(0)&Inf(1))|(Fin(1)&Inf(2))'
'|(Fin(3)|Inf(3))')) '|(Fin(3)|Inf(3))'))
test_rabin(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2),\ test_rabin(acc, True, [spot.rs_pair(m0, m1), spot.rs_pair(m1, m2),
spot.rs_pair(m3, mall), spot.rs_pair(mall, m3)]) spot.rs_pair(m3, mall), spot.rs_pair(mall, m3)])
acc = spot.acc_cond(spot.acc_code('(Fin(0)&Inf(1))|(Fin(1)&Inf(2))'\ acc = spot.acc_cond(spot.acc_code('(Fin(0)&Inf(1))|(Fin(1)&Inf(2))'
'|(Fin(3)|Inf(3))|(Fin(4)&Inf(5)&Inf(6))')) '|(Fin(3)|Inf(3))|(Fin(4)&Inf(5)&Inf(6))'))
test_rabin(acc, False, None) test_rabin(acc, False, None)

View file

@ -26,5 +26,5 @@ s = ""
for aut2 in si.split_on_sets(0, [0]): for aut2 in si.split_on_sets(0, [0]):
# This call to to_str() used to fail because split_on_sets had not # This call to to_str() used to fail because split_on_sets had not
# registered the atomic propositions of aut # registered the atomic propositions of aut
s += aut2.to_str(); s += aut2.to_str()
assert spot.automaton(s).num_states() == 8 assert spot.automaton(s).num_states() == 8

View file

@ -24,7 +24,7 @@ formulas = [('(Gp0 | Fp1) M 1', False, True),
('(p1 | (Fp0 R (p1 W p0))) M 1', True, True), ('(p1 | (Fp0 R (p1 W p0))) M 1', True, True),
('!G(F(p1 & Fp0) W p1)', False, True), ('!G(F(p1 & Fp0) W p1)', False, True),
('X(!p0 W Xp1)', False, False), ('X(!p0 W Xp1)', False, False),
('FG(p0)', False, True) ] ('FG(p0)', False, True)]
for f, isd, issd in formulas: for f, isd, issd in formulas:
print(f) print(f)

View file

@ -24,9 +24,9 @@ import spot
# Test case reduced from a report from Juraj Major <major@fi.muni.cz>. # Test case reduced from a report from Juraj Major <major@fi.muni.cz>.
a = spot.make_twa_graph(spot._bdd_dict) a = spot.make_twa_graph(spot._bdd_dict)
a.set_acceptance(0, spot.acc_code("t")) a.set_acceptance(0, spot.acc_code("t"))
assert(a.prop_state_acc() == True); assert(a.prop_state_acc() == True)
a.set_acceptance(1, spot.acc_code("Fin(0)")) a.set_acceptance(1, spot.acc_code("Fin(0)"))
assert(a.prop_state_acc() == spot.trival.maybe()); assert(a.prop_state_acc() == spot.trival.maybe())
# Some tests for used_inf_fin_sets(), which return a pair of mark_t. # Some tests for used_inf_fin_sets(), which return a pair of mark_t.
@ -34,8 +34,8 @@ assert(a.prop_state_acc() == spot.trival.maybe());
assert inf == [] assert inf == []
assert fin == [0] assert fin == [0]
(inf, fin) = spot.acc_code("(Fin(0)|Inf(1))&Fin(2)&Inf(0)").used_inf_fin_sets() (inf, fin) = spot.acc_code("(Fin(0)|Inf(1))&Fin(2)&Inf(0)").used_inf_fin_sets()
assert inf == [0,1] assert inf == [0, 1]
assert fin == [0,2] assert fin == [0, 2]
# is_rabin_like() returns (bool, [(inf, fin), ...]) # is_rabin_like() returns (bool, [(inf, fin), ...])
(b, v) = spot.acc_cond("(Fin(0)&Inf(1))|(Fin(2)&Inf(0))").is_rabin_like() (b, v) = spot.acc_cond("(Fin(0)&Inf(1))|(Fin(2)&Inf(0))").is_rabin_like()
@ -51,7 +51,7 @@ assert len(v) == 0
(b, v) = spot.acc_cond("(Fin(0)|Inf(1))&(Fin(2)|Inf(0))").is_streett_like() (b, v) = spot.acc_cond("(Fin(0)|Inf(1))&(Fin(2)|Inf(0))").is_streett_like()
assert b == True assert b == True
assert repr(v) == \ assert repr(v) == \
'(spot.rs_pair(fin=[0], inf=[1]), spot.rs_pair(fin=[2], inf=[0]))' '(spot.rs_pair(fin=[0], inf=[1]), spot.rs_pair(fin=[2], inf=[0]))'
v2 = (spot.rs_pair(fin=[0], inf=[1]), spot.rs_pair(fin=[2], inf=[0])) v2 = (spot.rs_pair(fin=[0], inf=[1]), spot.rs_pair(fin=[2], inf=[0]))
assert v == v2 assert v == v2

View file

@ -25,25 +25,25 @@ bdd_setvarnum(5)
V = [bdd_ithvar(i) for i in range(5)] V = [bdd_ithvar(i) for i in range(5)]
a = V[0] & -V[1] & V[2] & -V[3] a = V[0] & -V[1] & V[2] & -V[3]
b = 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] c = -V[0] & V[1] & -V[2] & -V[3]
assert(c == bdd_setxor(a,b)) assert(c == bdd_setxor(a, b))
assert(c == bdd_setxor(b,a)) assert(c == bdd_setxor(b, a))
assert(a == bdd_setxor(b,c)) assert(a == bdd_setxor(b, c))
assert(a == bdd_setxor(c,b)) assert(a == bdd_setxor(c, b))
assert(b == bdd_setxor(a,c)) assert(b == bdd_setxor(a, c))
assert(b == bdd_setxor(c,a)) assert(b == bdd_setxor(c, a))
d = V[1] & V[2] & -V[3] & V[4] d = V[1] & V[2] & -V[3] & V[4]
e = V[0] & 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(a, d))
assert(e == bdd_setxor(d,a)) assert(e == bdd_setxor(d, a))
# Cleanup all BDD variables before calling bdd_done(), otherwise # Cleanup all BDD variables before calling bdd_done(), otherwise
# bdd_delref will be called after bdd_done() and this is unsafe in # bdd_delref will be called after bdd_done() and this is unsafe in
# optimized builds. # optimized builds.
V = a = b = c = d = e = 0; V = a = b = c = d = e = 0
bdd_done() bdd_done()

View file

@ -19,10 +19,14 @@
import spot import spot
def incl(a,b):
def incl(a, b):
return not b.intersects(spot.dualize(spot.tgba_determinize(a))) return not b.intersects(spot.dualize(spot.tgba_determinize(a)))
def equiv(a,b):
return incl(a,b) and incl(b,a)
def equiv(a, b):
return incl(a, b) and incl(b, a)
def do_split(f, in_list): def do_split(f, in_list):
aut = spot.translate(f) aut = spot.translate(f)
@ -30,7 +34,8 @@ def do_split(f, in_list):
for a in in_list: for a in in_list:
inputs &= spot.buddy.bdd_ithvar(aut.get_dict().varnum(spot.formula(a))) inputs &= spot.buddy.bdd_ithvar(aut.get_dict().varnum(spot.formula(a)))
s = spot.split_2step(aut, inputs) s = spot.split_2step(aut, inputs)
return aut,s return aut, s
aut, s = do_split('(FG !a) <-> (GF b)', ['a']) aut, s = do_split('(FG !a) <-> (GF b)', ['a'])
assert equiv(aut, spot.unsplit_2step(s)) assert equiv(aut, spot.unsplit_2step(s))
@ -58,46 +63,45 @@ State: 2
--END--""" --END--"""
aut, s = do_split('! ((G (req -> (F ack))) && (G (go -> (F grant))))', ['go', aut, s = do_split('! ((G (req -> (F ack))) && (G (go -> (F grant))))', ['go',
'req']) 'req'])
assert equiv(aut, spot.unsplit_2step(s)) assert equiv(aut, spot.unsplit_2step(s))
# FIXME s.to_str() is NOT the same on Debian stable and on Debian unstable # FIXME s.to_str() is NOT the same on Debian stable and on Debian unstable
# we should investigate this # we should investigate this
#assert s.to_str() == """HOA: v1 # assert s.to_str() == """HOA: v1
#States: 9 # States: 9
#Start: 0 # Start: 0
#AP: 4 "ack" "req" "go" "grant" # AP: 4 "ack" "req" "go" "grant"
#acc-name: Buchi # acc-name: Buchi
#Acceptance: 1 Inf(0) # Acceptance: 1 Inf(0)
#properties: trans-labels explicit-labels state-acc # properties: trans-labels explicit-labels state-acc
#--BODY-- # --BODY--
#State: 0 # State: 0
#[1&!2] 3 # [1&!2] 3
#[!1&!2] 4 # [!1&!2] 4
#[1&2] 5 # [1&2] 5
#[!1&2] 6 # [!1&2] 6
#State: 1 # State: 1
#[t] 7 # [t] 7
#State: 2 # State: 2
#[t] 8 # [t] 8
#State: 3 # State: 3
#[t] 0 # [t] 0
#[!0] 1 # [!0] 1
#State: 4 # State: 4
#[t] 0 # [t] 0
#State: 5 # State: 5
#[t] 0 # [t] 0
#[!0] 1 # [!0] 1
#[!3] 2 # [!3] 2
#State: 6 # State: 6
#[t] 0 # [t] 0
#[!3] 2 # [!3] 2
#State: 7 {0} # State: 7 {0}
#[!0] 1 # [!0] 1
#State: 8 {0} # State: 8 {0}
#[!3] 2 # [!3] 2
#--END--""" # --END--"""
aut, s = do_split('((G (((! g_0) || (! g_1)) && ((r_0 && (X r_1)) -> (F (g_0 \ aut, s = do_split('((G (((! g_0) || (! g_1)) && ((r_0 && (X r_1)) -> (F (g_0 \
&& g_1))))) && (G (r_0 -> F g_0))) && (G (r_1 -> F g_1))', ['r_0', 'r_1']) && g_1))))) && (G (r_0 -> F g_0))) && (G (r_1 -> F g_1))', ['r_0', 'r_1'])
assert equiv(aut, spot.unsplit_2step(s)) assert equiv(aut, spot.unsplit_2step(s))

View file

@ -23,27 +23,29 @@ import os
import shutil import shutil
import sys import sys
def tgba(a): def tgba(a):
if not a.is_existential(): if not a.is_existential():
a = spot.remove_alternation(a) a = spot.remove_alternation(a)
a = spot.to_generalized_buchi(a) a = spot.to_generalized_buchi(a)
return a return a
def test_aut(aut): def test_aut(aut):
stgba = tgba(aut) stgba = tgba(aut)
assert stgba.equivalent_to(aut) assert stgba.equivalent_to(aut)
os.environ["SPOT_STREETT_CONV_MIN"] = '1' os.environ["SPOT_STREETT_CONV_MIN"] = '1'
sftgba = tgba(aut) sftgba = tgba(aut)
del os.environ["SPOT_STREETT_CONV_MIN"] del os.environ["SPOT_STREETT_CONV_MIN"]
assert stgba.equivalent_to(sftgba) assert stgba.equivalent_to(sftgba)
slike = spot.simplify_acceptance(aut) slike = spot.simplify_acceptance(aut)
sltgba = tgba(slike) sltgba = tgba(slike)
os.environ["SPOT_STREETT_CONV_MIN"] = "1" os.environ["SPOT_STREETT_CONV_MIN"] = "1"
slftgba = tgba(slike) slftgba = tgba(slike)
del os.environ["SPOT_STREETT_CONV_MIN"] del os.environ["SPOT_STREETT_CONV_MIN"]
assert sltgba.equivalent_to(slftgba) assert sltgba.equivalent_to(slftgba)
# Those automata are generated with ltl2dstar, which is NOT part of spot, # Those automata are generated with ltl2dstar, which is NOT part of spot,
# using the following command: # using the following command:
@ -51,11 +53,12 @@ def test_aut(aut):
# ltldo "ltl2dstar --automata=streett --output-format=hoa\ # ltldo "ltl2dstar --automata=streett --output-format=hoa\
# --ltl2nba=spin:ltl2tgba@-s %L ->%O" -F- --name=%f -H" # --ltl2nba=spin:ltl2tgba@-s %L ->%O" -F- --name=%f -H"
if shutil.which('ltl2dstar') is None: if shutil.which('ltl2dstar') is None:
sys.exit(77) sys.exit(77)
for a in spot.automata('genltl --eh-patterns --dac-patterns --hkrss-patterns\ for a in spot.automata('genltl --eh-patterns --dac-patterns --hkrss-patterns\
--sb-patterns |\ --sb-patterns |\
ltldo "ltl2dstar --automata=streett --output-format=hoa\ ltldo "ltl2dstar --automata=streett --output-format=hoa\
--ltl2nba=spin:ltl2tgba@-s %L ->%O"\ --ltl2nba=spin:ltl2tgba@-s %L ->%O"\
-T5 -F- --name=%f -H|'): -T5 -F- --name=%f -H|'):
test_aut(a) test_aut(a)

View file

@ -24,6 +24,7 @@
import spot import spot
def explain_stut(f): def explain_stut(f):
f = spot.formula(f) f = spot.formula(f)
pos = spot.translate(f) pos = spot.translate(f)
@ -41,6 +42,7 @@ def explain_stut(f):
word2.simplify() word2.simplify()
return(word, word2) return(word, word2)
# Test from issue #388 # Test from issue #388
w1, w2 = explain_stut('{(a:b) | (a;b)}|->Gc') w1, w2 = explain_stut('{(a:b) | (a;b)}|->Gc')
assert str(w1) == 'a & !b & !c; cycle{!a & b & !c}' assert str(w1) == 'a & !b & !c; cycle{!a & b & !c}'

View file

@ -46,37 +46,39 @@ rg = spot.randltlgenerator(2, opts)
dict = spot.make_bdd_dict() dict = spot.make_bdd_dict()
def produce_phi(rg, n): def produce_phi(rg, n):
phi = [] phi = []
while len(phi) < n: while len(phi) < n:
f = rg.next() f = rg.next()
if f.is_syntactic_persistence(): if f.is_syntactic_persistence():
phi.append(f) phi.append(f)
return phi return phi
phi1 = produce_phi(rg, 1000) phi1 = produce_phi(rg, 1000)
phi2 = produce_phi(rg, 1000) phi2 = produce_phi(rg, 1000)
inputres = [] inputres = []
aut = [] aut = []
for p in zip(phi1, phi2): for p in zip(phi1, phi2):
inputres.append(spot.formula.Or(p)) inputres.append(spot.formula.Or(p))
a1 = spot.ltl_to_tgba_fm(p[0], dict) a1 = spot.ltl_to_tgba_fm(p[0], dict)
a2 = spot.ltl_to_tgba_fm(p[1], dict) a2 = spot.ltl_to_tgba_fm(p[1], dict)
aut.append(spot.to_generalized_buchi( \ aut.append(spot.to_generalized_buchi(
spot.remove_alternation(spot.sum(a1, a2), True))) spot.remove_alternation(spot.sum(a1, a2), True)))
for p in zip(aut, inputres): for p in zip(aut, inputres):
assert p[0].equivalent_to(p[1]) assert p[0].equivalent_to(p[1])
aut = [] aut = []
inputres = [] inputres = []
for p in zip(phi1, phi2): for p in zip(phi1, phi2):
inputres.append(spot.formula.And(p)) inputres.append(spot.formula.And(p))
a1 = spot.ltl_to_tgba_fm(p[0], dict) a1 = spot.ltl_to_tgba_fm(p[0], dict)
a2 = spot.ltl_to_tgba_fm(p[1], dict) a2 = spot.ltl_to_tgba_fm(p[1], dict)
aut.append(spot.to_generalized_buchi( \ aut.append(spot.to_generalized_buchi(
spot.remove_alternation(spot.sum_and(a1, a2), True))) spot.remove_alternation(spot.sum_and(a1, a2), True)))
for p in zip(aut, inputres): for p in zip(aut, inputres):
assert p[0].equivalent_to(p[1]) assert p[0].equivalent_to(p[1])

View file

@ -46,6 +46,6 @@ for f in spot.randltl(5, 2000):
assert spot.are_equivalent(n, p) assert spot.are_equivalent(n, p)
# Issue #390. # Issue #390.
a = spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det'); a = spot.translate('!(GFa -> (GFb & GF(!b & !Xb)))', 'gen', 'det')
b = spot.to_parity(a); b = spot.to_parity(a)
assert a.equivalent_to(b) assert a.equivalent_to(b)

View file

@ -29,11 +29,13 @@ GF!b
(b & GF!b) | (!b & FGb) (b & GF!b) | (!b & FGb)
b | (a & XF(b R a)) | (!a & XG(!b U !a))""" b | (a & XF(b R a)) | (!a & XG(!b U !a))"""
def test_phi(phi): def test_phi(phi):
a = spot.translate(phi, 'TGBA', 'SBAcc') a = spot.translate(phi, 'TGBA', 'SBAcc')
res = spot.to_weak_alternating(spot.dualize(a)) res = spot.to_weak_alternating(spot.dualize(a))
assert res.equivalent_to(spot.formula.Not(spot.formula(phi))) assert res.equivalent_to(spot.formula.Not(spot.formula(phi)))
for p in phi1.split('\n'): for p in phi1.split('\n'):
print(p) print(p)
test_phi(p) test_phi(p)

View file

@ -39,9 +39,9 @@ assert v4 == spot.trival(spot.trival.maybe_value)
assert v3 assert v3
assert -v2 assert -v2
assert not -v1 assert not -v1
assert not v1; assert not v1
assert not -v3 assert not -v3
for u in (v1, v2, v3): for u in (v1, v2, v3):
for v in (v1, v2, v3): for v in (v1, v2, v3):
assert (u & v) == -(-u | -v) assert (u & v) == -(-u | -v)