added test for f_neg_canonical form
This commit is contained in:
parent
c495216626
commit
f7f322148e
3 changed files with 33 additions and 14 deletions
16
stl/ast.py
16
stl/ast.py
|
|
@ -41,7 +41,7 @@ class AST(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return set()
|
return tuple()
|
||||||
|
|
||||||
def walk(self):
|
def walk(self):
|
||||||
"""Walk of the AST."""
|
"""Walk of the AST."""
|
||||||
|
|
@ -123,7 +123,7 @@ class AtomicPred(namedtuple("AP", ["id"]), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return set()
|
return tuple()
|
||||||
|
|
||||||
|
|
||||||
class LinEq(namedtuple("LinEquality", ["terms", "op", "const"]), AST):
|
class LinEq(namedtuple("LinEquality", ["terms", "op", "const"]), AST):
|
||||||
|
|
@ -134,7 +134,7 @@ class LinEq(namedtuple("LinEquality", ["terms", "op", "const"]), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return set()
|
return tuple()
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# TODO: compute hash based on contents
|
# TODO: compute hash based on contents
|
||||||
|
|
@ -171,7 +171,7 @@ class NaryOpSTL(namedtuple('NaryOp', ['args']), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return set(self.args)
|
return tuple(self.args)
|
||||||
|
|
||||||
|
|
||||||
class Or(NaryOpSTL):
|
class Or(NaryOpSTL):
|
||||||
|
|
@ -203,7 +203,7 @@ class ModalOp(namedtuple('ModalOp', ['interval', 'arg']), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return {self.arg}
|
return (self.arg,)
|
||||||
|
|
||||||
|
|
||||||
class F(ModalOp):
|
class F(ModalOp):
|
||||||
|
|
@ -232,7 +232,7 @@ class Until(namedtuple('ModalOp', ['arg1', 'arg2']), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return {self.arg1, self.arg2}
|
return (self.arg1, self.arg2)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# TODO: compute hash based on contents
|
# TODO: compute hash based on contents
|
||||||
|
|
@ -247,7 +247,7 @@ class Neg(namedtuple('Neg', ['arg']), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return {self.arg}
|
return (self.arg,)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# TODO: compute hash based on contents
|
# TODO: compute hash based on contents
|
||||||
|
|
@ -262,7 +262,7 @@ class Next(namedtuple('Next', ['arg']), AST):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
return {self.arg}
|
return (self.arg,)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# TODO: compute hash based on contents
|
# TODO: compute hash based on contents
|
||||||
|
|
|
||||||
13
stl/test_utils.py
Normal file
13
stl/test_utils.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import stl
|
||||||
|
from stl.hypothesis import SignalTemporalLogicStrategy
|
||||||
|
|
||||||
|
from hypothesis import given
|
||||||
|
|
||||||
|
|
||||||
|
@given(SignalTemporalLogicStrategy)
|
||||||
|
def test_f_neg_or_canonical_form(phi):
|
||||||
|
phi2 = stl.utils.f_neg_or_canonical_form(phi)
|
||||||
|
phi3 = stl.utils.f_neg_or_canonical_form(phi2)
|
||||||
|
assert phi2 == phi3
|
||||||
|
assert not any(
|
||||||
|
isinstance(x, (stl.ast.G, stl.ast.And)) for x in phi2.walk())
|
||||||
18
stl/utils.py
18
stl/utils.py
|
|
@ -5,7 +5,9 @@ import traces
|
||||||
from lenses import bind
|
from lenses import bind
|
||||||
|
|
||||||
import stl.ast
|
import stl.ast
|
||||||
from stl.ast import (And, F, G, Interval, LinEq, Neg, Or, AP_lens)
|
from stl.ast import (And, F, G, Interval, LinEq, Neg,
|
||||||
|
Or, AP_lens, Next, Until, AtomicPred,
|
||||||
|
_Top, _Bot)
|
||||||
from stl.types import STL
|
from stl.types import STL
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,24 +15,28 @@ oo = float('inf')
|
||||||
|
|
||||||
|
|
||||||
def f_neg_or_canonical_form(phi: STL) -> STL:
|
def f_neg_or_canonical_form(phi: STL) -> STL:
|
||||||
if isinstance(phi, LinEq):
|
if isinstance(phi, (LinEq, AtomicPred, _Top, _Bot)):
|
||||||
return phi
|
return phi
|
||||||
|
|
||||||
children = [f_neg_or_canonical_form(s) for s in phi.children]
|
children = [f_neg_or_canonical_form(s) for s in phi.children]
|
||||||
if isinstance(phi, (And, G)):
|
if isinstance(phi, (And, G)):
|
||||||
children = [Neg(s) for s in children]
|
children = [Neg(s) for s in children]
|
||||||
children = tuple(children)
|
children = tuple(sorted(children, key=str))
|
||||||
|
|
||||||
if isinstance(phi, Or):
|
if isinstance(phi, Or):
|
||||||
return Or(children)
|
return Or(children)
|
||||||
elif isinstance(phi, And):
|
elif isinstance(phi, And):
|
||||||
return Neg(Or(children))
|
return Neg(Or(children))
|
||||||
elif isinstance(phi, Neg):
|
elif isinstance(phi, Neg):
|
||||||
return Neg(children[0])
|
return Neg(*children)
|
||||||
|
elif isinstance(phi, Next):
|
||||||
|
return Next(*children)
|
||||||
|
elif isinstance(phi, Until):
|
||||||
|
return Until(*children)
|
||||||
elif isinstance(phi, F):
|
elif isinstance(phi, F):
|
||||||
return F(phi.interval, children[0])
|
return F(phi.interval, *children)
|
||||||
elif isinstance(phi, G):
|
elif isinstance(phi, G):
|
||||||
return Neg(F(phi.interval, children[0]))
|
return Neg(F(phi.interval, *children))
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue