def test_weak_until_noloop(self): with tests.Configure(self, __file__, "/example.smv"): enc = self.enc a = ast.Proposition("a") b = ast.Proposition("b") expr = ast.WeakUntil(a, b) tool = expr.semantic_no_loop(enc, 0, 2) manual = (b.semantic_no_loop(enc, 0, 2) | (a.semantic_no_loop(enc, 0, 2) & (b.semantic_no_loop(enc, 1, 2) | (a.semantic_no_loop(enc, 1, 2) & (b.semantic_no_loop(enc, 2, 2)))))) spec = Node.from_ptr(parse_ltl_spec("a U b")) nusmv = ltlspec.bounded_semantics(self.befsm, spec, bound=2, loop=bmcutils.no_loopback()) # normalized string representation of the BE's (make them comparable) s_tool = tests.canonical_cnf(tool) s_nusmv = tests.canonical_cnf(nusmv) s_manual = tests.canonical_cnf(manual) self.assertEqual(s_tool, s_manual) self.assertEqual(s_tool, s_nusmv)
def test_until_with_loop(self): with tests.Configure(self, __file__, "/example.smv"): enc = self.enc i, k, l = 0, 2, 0 a = ast.Proposition("a") b = ast.Proposition("b") expr = ast.Until(a, b) tool = expr.semantic_with_loop(enc, i, k, l) manual = b.semantic_with_loop(enc, i, k, l) | \ (a.semantic_with_loop(enc, i, k, l) & b.semantic_with_loop(enc, i+1, k, l)) spec = Node.from_ptr(parse_ltl_spec("a U b")) nusmv = ltlspec.bounded_semantics(self.befsm, spec, bound=k, loop=l) tool &= bmcutils.loop_condition(enc, k, l) manual &= bmcutils.loop_condition(enc, k, l) # normalized string representation of the BE's (make them comparable) s_tool = tests.canonical_cnf(tool) s_nusmv = tests.canonical_cnf(nusmv) s_manual = tests.canonical_cnf(manual) self.assertEqual(s_tool, s_manual) self.assertEqual(s_tool, s_nusmv)
def test_not_with_loop(self): with tests.Configure(self, __file__, "/example.smv"): # constant expr = ast.Not(ast.Constant("TRUE")) self.assertEqual( ast.Constant("FALSE").semantic_with_loop(self.enc, 2, 3, 1), expr.semantic_with_loop(self.enc, 2, 3, 1)) # variable expr = ast.Not(ast.Proposition("a")) self.assertEqual( -ast.Proposition("a").semantic_with_loop(self.enc, 2, 3, 1), expr.semantic_with_loop(self.enc, 2, 3, 1)) # not expr = ast.Not(ast.Not(ast.Proposition("a"))) self.assertEqual( ast.Proposition("a").semantic_with_loop(self.enc, 2, 3, 1), expr.semantic_with_loop(self.enc, 2, 3, 1)) # expression: and expr = ast.Not(ast.And(ast.Proposition("a"), ast.Proposition("b"))) self.assertEqual( -(ast.Proposition("a").semantic_with_loop(self.enc, 2, 3, 1) & ast.Proposition("b").semantic_with_loop(self.enc, 2, 3, 1)), expr.semantic_with_loop(self.enc, 2, 3, 1)) # expression: weak until expr = ast.WeakUntil(ast.Proposition("a"), ast.Proposition("b")) nega = ast.Not(expr) self.assertEqual(-expr.semantic_with_loop(self.enc, 2, 3, 1), nega.semantic_with_loop(self.enc, 2, 3, 1))
def test_eventually_with_loop(self): with tests.Configure(self, __file__, "/example.smv"): i, k, l = 0, 2, 0 enc = self.enc a = ast.Proposition("a") formula = ast.Eventually(a) tool = formula.semantic_with_loop(enc, i, k, l) manual = a.semantic_with_loop(enc, i+1, k, l) |\ a.semantic_with_loop(enc, i , k, l) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("F a")), bound=k, loop=l) # normalized string representation of the BE's (make them comparable) loop_cond = bmcutils.loop_condition(enc, k, l) s_tool = tests.canonical_cnf(tool & loop_cond) s_manual = tests.canonical_cnf(manual & loop_cond) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_nusmv, s_tool) self.assertEqual(s_manual, s_tool)
def test_next_with_loop(self): with tests.Configure(self, __file__, "/example.smv"): i, k, l = 0, 2, 0 enc = self.enc # One step a = ast.Proposition("a") formula = ast.Next(a) tool = formula.semantic_with_loop(enc, i, k, l) manual = a.semantic_with_loop(enc, 1, k, l) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("X a")), bound=k, loop=l) loop_cond = bmcutils.loop_condition(enc, k, l) s_tool = tests.canonical_cnf(tool & loop_cond) s_manual = tests.canonical_cnf(manual & loop_cond) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_tool, s_nusmv) self.assertEqual(s_tool, s_manual) # two steps formula = ast.Next(ast.Next(a)) tool = formula.semantic_with_loop(enc, i, k, l) manual = a.semantic_with_loop(enc, 0, k, l) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("X X a")), bound=k, loop=l) loop_cond = bmcutils.loop_condition(enc, k, l) s_tool = tests.canonical_cnf(tool & loop_cond) s_manual = tests.canonical_cnf(manual & loop_cond) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_tool, s_nusmv) self.assertEqual(s_tool, s_manual) # Three steps (getting over k) formula = ast.Next(ast.Next(ast.Next(a))) tool = formula.semantic_with_loop(enc, i, k, l) manual = a.semantic_with_loop(enc, 1, k, l) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("X X X a")), bound=k, loop=l) loop_cond = bmcutils.loop_condition(enc, k, l) s_tool = tests.canonical_cnf(tool & loop_cond) s_manual = tests.canonical_cnf(manual & loop_cond) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_tool, s_nusmv) self.assertEqual(s_tool, s_manual)
def test_variable_noloop(self): with tests.Configure(self, __file__, "/example.smv"): expr = ast.Proposition("a") self.assertEqual( self.enc.by_name['a'].at_time[3].boolean_expression, expr.semantic_no_loop(self.enc, 3, 5)) # bound has little impact on the BE for a variable self.assertEqual( self.enc.by_name['a'].at_time[3].boolean_expression, expr.semantic_no_loop(self.enc, 3, 3))
def test_globally_no_loop(self): with tests.Configure(self, __file__, "/example.smv"): i, k = 0, 2 enc = self.enc mgr = enc.manager a = ast.Proposition("a") formula = ast.Globally(a) tool = formula.semantic_no_loop(enc, i, k) self.assertEqual(Be.false(mgr), tool)
def test_next_noloop(self): with tests.Configure(self, __file__, "/example.smv"): i, k = 0, 2 enc = self.enc # One step a = ast.Proposition("a") formula = ast.Next(a) tool = formula.semantic_no_loop(enc, i, k) manual = a.semantic_no_loop(enc, 1, k) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("X a")), bound=k, loop=bmcutils.no_loopback()) s_tool = tests.canonical_cnf(tool) s_manual = tests.canonical_cnf(manual) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_tool, s_nusmv) self.assertEqual(s_tool, s_manual) # two steps formula = ast.Next(ast.Next(a)) tool = formula.semantic_no_loop(enc, i, k) manual = a.semantic_no_loop(enc, 2, k) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("X X a")), bound=k, loop=bmcutils.no_loopback()) s_tool = tests.canonical_cnf(tool) s_manual = tests.canonical_cnf(manual) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_tool, s_nusmv) self.assertEqual(s_tool, s_manual) # Three steps (getting over k) formula = ast.Next(ast.Next(ast.Next(a))) tool = formula.semantic_no_loop(enc, i, k) manual = Be.false(enc.manager) nusmv = ltlspec.bounded_semantics(self.befsm, Node.from_ptr( parse_ltl_spec("X X X a")), bound=k, loop=bmcutils.no_loopback()) s_tool = tests.canonical_cnf(tool) s_manual = tests.canonical_cnf(manual) s_nusmv = tests.canonical_cnf(nusmv) self.assertEqual(s_tool, s_nusmv) self.assertEqual(s_tool, s_manual)
def test_variable_withloop(self): with tests.Configure(self, __file__, "/example.smv"): # bound and loop have no impact on the way BE for a variable is # generated (successor index not enforced) expr = ast.Proposition("a") self.assertEqual( self.enc.by_name['a'].at_time[3].boolean_expression, expr.semantic_with_loop(self.enc, 3, 5, 2)) self.assertEqual( self.enc.by_name['a'].at_time[3].boolean_expression, expr.semantic_with_loop(self.enc, 3, 3, 3))
def test_imply_noloop(self): with tests.Configure(self, __file__, "/example.smv"): expr = ast.Imply(ast.Proposition("a"), ast.Proposition("b")) self.assertEqual( (ast.Proposition("a").semantic_no_loop(self.enc, 2, 3).imply( ast.Proposition("b").semantic_no_loop(self.enc, 2, 3))), expr.semantic_no_loop(self.enc, 2, 3)) expr = ast.Imply(ast.Globally(ast.Proposition("a")), ast.Eventually(ast.Proposition("b"))) self.assertEqual( (-ast.Globally(ast.Proposition("a")).semantic_no_loop( self.enc, 2, 3) | ast.Eventually(ast.Proposition("b")).semantic_no_loop( self.enc, 2, 3)), expr.semantic_no_loop(self.enc, 2, 3))
def test_weak_until_with_loop(self): with tests.Configure(self, __file__, "/example.smv"): enc = self.enc mgr = enc.manager i, k, l = 0, 2, 0 a = ast.Proposition("a") b = ast.Proposition("b") expr = ast.WeakUntil(a, b) tool = expr.semantic_with_loop(enc, i, k, l) manual = b.semantic_with_loop(enc, i, k, l) | \ (a.semantic_with_loop(enc, i, k, l) & \ (b.semantic_with_loop(enc, i+1, k, l) | \ a.semantic_with_loop(enc, i+1, k, l) & Be.true(mgr) ) ) # normalized string representation of the BE's (make them comparable) s_tool = tests.canonical_cnf(tool) s_manual = tests.canonical_cnf(manual) self.assertEqual(s_tool, s_manual)
def test_xor_with_loop(self): with tests.Configure(self, __file__, "/example.smv"): expr = ast.Xor(ast.Proposition("a"), ast.Proposition("b")) self.assertEqual( (ast.Proposition("a").semantic_with_loop(self.enc, 2, 3, 1) ^ ast.Proposition("b").semantic_with_loop(self.enc, 2, 3, 1)), expr.semantic_with_loop(self.enc, 2, 3, 1)) expr = ast.Xor(ast.Globally(ast.Proposition("a")), ast.Eventually(ast.Proposition("b"))) self.assertEqual( (ast.Globally(ast.Proposition("a")).semantic_with_loop( self.enc, 2, 3, 1) ^ ast.Eventually(ast.Proposition("b")).semantic_with_loop( self.enc, 2, 3, 1)), expr.semantic_with_loop(self.enc, 2, 3, 1))
def make_plain_proposition(s,l,tokens): """ This parse action makes a plain Proposition (as defined in :see:`pynusmv_tools.bmcLTL.ast.Proposition`) from the parsed text. .. note:: This action 'flattens' the expression; meaning that the result of the parsing of a complex proposition such as '(a + b) << 4 >= c - 6' will result in one single `Proposition` blob instead of being decomposed. Namely, the previous example would yield:: ast.Proposition( (a + b) << 4 >= c - 6 ) This is a design choice motivated by the fact that: 1. the objective of this tool is to illustrate the functioning of LTL bounded model checking and how its reduction to propositional satisfiability (SAT) can be implemented with PyNuSMV as if it were a brand new logical formalism; not to demonstrate how relational and arithmetic expressions can be booleanized. 2. the expressions represented this way do not contain any of the logical connectives which are part of LTL syntax and are as such out of the scope of this tool. (They can have no impact on the generated BMC problem). 3. Relational and arithmetic operators are only provided for the sake of being able to perform useful verification on realistic like models without being forced to go through the burden of defining DEFINE for each of the expressions used. .. note:: You should really not worry to much about the meaning of the parameters, there are inherited from the parseAction protocol. :param s: the original string corresponding to the text that has been parsed :param l: the location in the string where matching started :param tokens: the list of the matched tokens (actually a :see:`pyparsing.ParseResult`) :return: a `Proposition` ast node encapsulating the parsed expression. """ members = tokens[0] text_of = lambda x: '('+x.id+')' if hasattr(x, 'id') else x members = list(map(text_of, members)) return ast.Proposition(' '.join(members))
""" This module contains the class definition of the symbols and grammar of an LTL formula """ import pyparsing as pp import pynusmv_tools.bmcLTL.ast as ast ############################################################################### # Symbols and keywords ############################################################################### # terminals number = pp.Regex("[0-9]+").setParseAction(lambda s,l,t: ast.Constant(t[0])) variable = pp.Regex("[a-zA-Z_@]+[a-zA-Z0-9_@.]*").setParseAction(lambda s,l,t: ast.Proposition(t[0])) true = pp.Keyword("TRUE" ).setParseAction(lambda s,l,t: ast.Constant("TRUE")) false = pp.Keyword("FALSE").setParseAction(lambda s,l,t: ast.Constant("FALSE")) # temporal operators op_G = pp.Literal("[]") op_F = pp.Literal("<>") op_X = pp.Literal("()") op_U = pp.Keyword("U") op_W = pp.Keyword("W") # propositional operators op_not = pp.Literal("!") op_and = pp.Literal("&") op_or = pp.Literal("|") op_xor = pp.Literal("^") op_impl = pp.Literal("=>")