simplify parser + start removing lineq code

This commit is contained in:
Marcell Vazquez-Chanlatte 2018-09-06 01:19:06 -07:00
parent 7798fe679e
commit b9b10ac835
11 changed files with 143 additions and 247 deletions

View file

@ -2,58 +2,53 @@
# TODO: allow multiplication to be distributive
# TODO: support variables on both sides of ineq
from functools import partialmethod
import operator as op
from functools import partialmethod, reduce
from lenses import bind
from parsimonious import Grammar, NodeVisitor
from stl import ast
from stl.utils import iff, implies, xor
from stl.utils import iff, implies, xor, timed_until
STL_GRAMMAR = Grammar(u'''
phi = (timed_until / until / neg / next / g / f / lineq / AP / or / and
/ implies / xor / iff / paren_phi / bot / top)
phi = (neg / paren_phi / next / bot / top
/ xor_outer / iff_outer / implies_outer / and_outer / or_outer
/ timed_until / until / g / f / AP)
paren_phi = "(" __ phi __ ")"
neg = ("~" / "¬") __ phi
next = ("@" / "X") __ phi
or = paren_phi _ ("" / "or" / "|") _ (or / paren_phi)
and = paren_phi _ ("" / "and" / "&") _ (and / paren_phi)
implies = paren_phi _ ("" / "->") _ (and / paren_phi)
iff = paren_phi _ ("" / "<->" / "iff") _ (and / paren_phi)
xor = paren_phi _ ("" / "^" / "xor") _ (and / paren_phi)
and_outer = "(" __ and_inner __ ")"
and_inner = (phi __ ("" / "and" / "&") __ and_inner) / phi
neg = ("~" / "¬") paren_phi
next = next_sym paren_phi
f = F interval? phi
g = G interval? phi
until = paren_phi __ U __ paren_phi
timed_until = paren_phi __ U interval __ paren_phi
or_outer = "(" __ or_inner __ ")"
or_inner = (phi __ ("" / "or" / "|") __ or_inner) / phi
next_sym = "X" / ""
F = "F" / ""
G = "G" / ""
U = "U"
implies_outer = "(" __ implies_inner __ ")"
implies_inner = (phi __ ("" / "->") __ implies_inner) / phi
iff_outer = "(" __ iff_inner __ ")"
iff_inner = (phi __ ("" / "<->" / "iff") __ iff_inner) / phi
xor_outer = "(" __ xor_inner __ ")"
xor_inner = (phi __ ("" / "^" / "xor") __ xor_inner) / phi
f = ("< >" / "F") interval? __ phi
g = ("[ ]" / "G") interval? __ phi
until = "(" __ phi _ "U" _ phi __ ")"
timed_until = "(" __ phi _ "U" interval _ phi __ ")"
interval = "[" __ const_or_unbound __ "," __ const_or_unbound __ "]"
const_or_unbound = unbound / "inf" / const
const_or_unbound = const / "inf" / id
lineq = terms _ op _ const_or_unbound
term = const? var
terms = (term __ pm __ terms) / term
AP = ~r"[a-z\d]+"
var = id
AP = ~r"[a-zA-z\d]+"
bot = "0"
top = "1"
bot = ""
top = ""
pm = "+" / "-"
dt = "dt"
unbound = id "?"
id = ~r"[a-zA-z\d]+"
id = ~r"[a-z\d]+"
const = ~r"[-+]?(\d*\.\d+|\d+)"
op = ">=" / "<=" / "<" / ">" / "="
_ = ~r"\s"+
__ = ~r"\s"*
EOL = "\\n"
@ -67,6 +62,32 @@ class STLVisitor(NodeVisitor):
super().__init__()
self.default_interval = ast.Interval(0.0, H)
def binop_inner(self, _, children):
if isinstance(children[0], ast.AST):
return children
((left, _, _, _, right),) = children
return [left] + right
def binop_outer(self, _, children, *, binop):
return reduce(binop, children[2])
def visit_const_or_unbound(self, node, children):
child = children[0]
return ast.Param(child) if isinstance(child, str) else float(node.text)
visit_and_inner = binop_inner
visit_iff_inner = binop_inner
visit_implies_inner = binop_inner
visit_or_inner = binop_inner
visit_xor_inner = binop_inner
visit_and_outer = partialmethod(binop_outer, binop=op.and_)
visit_iff_outer = partialmethod(binop_outer, binop=iff)
visit_implies_outer = partialmethod(binop_outer, binop=implies)
visit_or_outer = partialmethod(binop_outer, binop=op.or_)
visit_xor_outer = partialmethod(binop_outer, binop=xor)
def generic_visit(self, _, children):
return children
@ -83,80 +104,41 @@ class STLVisitor(NodeVisitor):
return ast.TOP
def visit_interval(self, _, children):
_, _, (left, ), _, _, _, (right, ), _, _ = children
left = left if left != [] else float("inf")
right = right if right != [] else float("inf")
_, _, left, _, _, _, right, _, _ = children
return ast.Interval(left, right)
def get_text(self, node, _):
return node.text
def visit_unbound(self, node, _):
return ast.Param(node.text)
visit_op = get_text
def unary_temp_op_visitor(self, _, children, op):
_, i, phi = children
_, i, _, phi = children
i = self.default_interval if not i else i[0]
return op(i, phi)
def binop_visitor(self, _, children, op):
phi1, _, _, _, (phi2, ) = children
argL = list(phi1.args) if isinstance(phi1, op) else [phi1]
argR = list(phi2.args) if isinstance(phi2, op) else [phi2]
return op(tuple(argL + argR))
def sugar_binop_visitor(self, _, children, op):
phi1, _, _, _, (phi2, ) = children
return op(phi1, phi2)
visit_f = partialmethod(unary_temp_op_visitor, op=ast.F)
visit_g = partialmethod(unary_temp_op_visitor, op=ast.G)
visit_or = partialmethod(binop_visitor, op=ast.Or)
visit_and = partialmethod(binop_visitor, op=ast.And)
visit_xor = partialmethod(sugar_binop_visitor, op=xor)
visit_iff = partialmethod(sugar_binop_visitor, op=iff)
visit_implies = partialmethod(sugar_binop_visitor, op=implies)
def visit_until(self, _, children):
phi1, _, _, _, phi2 = children
_, _, phi1, _, _, _, phi2, _, _ = children
return ast.Until(phi1, phi2)
def visit_timed_until(self, _, children):
_, _, phi1, _, _, itvl, _, phi2, _, _ = children
return timed_until(phi1, phi2, itvl.lower, itvl.upper)
def visit_id(self, name, _):
return name.text
def visit_const(self, const, children):
return float(const.text)
def visit_term(self, _, children):
coeffs, iden = children
c = coeffs[0] if coeffs else 1
return ast.Var(coeff=c, id=iden)
def visit_terms(self, _, children):
if isinstance(children[0], list):
term, _1, sgn, _2, terms = children[0]
terms = bind(terms)[0].coeff * sgn
return [term] + terms
else:
return children
def visit_lineq(self, _, children):
terms, _1, op, _2, const = children
return ast.LinEq(tuple(terms), op, const[0])
def visit_pm(self, node, _):
return 1 if node.text == "+" else -1
def visit_AP(self, *args):
return ast.AtomicPred(self.visit_id(*args))
def visit_neg(self, _, children):
return ~children[1]
return ~children[2]
def visit_next(self, _, children):
return ast.Next(children[1])
return ast.Next(children[2])
def parse(stl_str: str, rule: str = "phi", H=oo) -> "STL":