def test_constraint_context_sigma(self): fsm = master_be_fsm() _true = Node.from_ptr(parse_ltl_spec("TRUE")) _true = bmcutils.make_nnf_boolean_wff(_true) _truen= _true.to_node() cond = Wff(parse_ltl_spec("G !(mouse = hover)"))\ .to_boolean_wff()\ .to_negation_normal_form() off_1 = 0 off_2 = 2 length= 1 # sigma1 problem = diagnosability.generate_sat_problem([], (_truen, _truen), length, _true, cond.to_node(), _truen) tm_cond = ltlspec.bounded_semantics_at_offset(fsm, cond.to_node(), length, off_1) canonical_p = tests.canonical_cnf(problem) canonical_f = tests.canonical_cnf(tm_cond) self.assertTrue(all(clause in canonical_p for clause in canonical_f)) # sigma2 problem = diagnosability.generate_sat_problem([], (_truen, _truen), length, _true, _truen, cond.to_node()) tm_cond = ltlspec.bounded_semantics_at_offset(fsm, cond.to_node(), length, off_2) canonical_p = tests.canonical_cnf(problem) canonical_f = tests.canonical_cnf(tm_cond) self.assertTrue(all(clause in canonical_p for clause in canonical_f))
def generate_sat_problem(observable_vars, formula_nodes, length, theta, sigma1, sigma2): """ Generates a SAT problem which is satisfiable iff the given `formula` is *NOT* diagnosable for the loaded model for traces of length `length`. :param observable_vars: the list of the boolean variables that are considered visible in the scope of this diagnosability test :param formula: the node (NuSMV ast representation) representing the formula whose diagnosability is under verification :param length: the maximum length of the generated traces. :param theta: the initial condition placed on the initial belief state (in the form of a :see:`pynusmv.node.Node`) :param sigma1: the shape of the traces considered relevant for the first member of the critical pair in the ongoing diagnosability test (in the form of a :see:`pynusmv.node.Node`) :param sigma2: the shape of the traces considered relevant for the second member of the critical pair in the ongoing diagnosability test (in the form of a :see:`pynusmv.node.Node`) :return: a SAT problem which is satisfiable iff the given formula is not diagnosable on the loaded model. """ fsm = master_be_fsm() offset_1 = 0 offset_2 = length +1 problem = generate_path(offset_1, length) & generate_path(offset_2, length) \ & constraint_same_observations( observable_vars, offset_1, offset_2, length)\ & constraint_context_theta_initial(theta, offset_1, offset_2) \ & bounded_semantics_at_offset(fsm, sigma1, length, offset_1) \ & bounded_semantics_at_offset(fsm, sigma2, length, offset_2) \ & constraint_eventually_critical_pair( formula_nodes, offset_1, offset_2, length) return problem
def test_releases(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("(a V b)") # bound 0 offset = 0 bound = 0 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 0 bound = 1 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) # VERIFIED manually, complains only about the CNF clauses literals and that's OK. # self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 2 offset = 2 bound = 1 # because of the way the loop condition is encoded ! ref_expr= ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, bound, offset)\ | ( ltlspec.bounded_semantics_with_loop_at_offset(fsm, formula, 0, bound, 0, offset) & bmcutils.loop_condition(self.enc, offset+bound, offset+0)) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset)
def generate_sat_problem(fsm, fml, length): fsm = master_be_fsm() offset = 0 wff = bmcutils.make_negated_nnf_boolean_wff(fml).to_node() problem = generate_path(offset, length) \ & ltlspec.bounded_semantics_at_offset(fsm, wff, length, offset) return problem
def test_until(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("(a U !b)") # bound 0 offset = 0 bound = 0 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 0 bound = 1 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 0 offset = 2 bound = 0 cdr = Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) ref_expr= self.enc.shift_to_time(cdr, 0+offset) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 2 bound = 1 car = Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) cdr = Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) ref_expr= self.enc.shift_to_time(cdr, 0+offset) \ | (self.enc.shift_to_time(car, 0+offset) & self.enc.shift_to_time(cdr, 1+offset)) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr))
def test_globally(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("G (a <-> !b)") # bound 0 offset = 0 bound = 0 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 0 bound = 1 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 0 offset = 2 bound = 0 ref_expr= Be.false(self.enc.manager) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 2 bound = 1 ref_expr= ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, bound, offset) \ |( ltlspec.bounded_semantics_with_loop_at_offset(fsm, formula, 0, bound, 0, offset) \ & bmcutils.loop_condition(self.enc, bound+offset, offset)) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr))
def test_next(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("X (a <-> !b)") # bound 0 offset = 0 bound = 0 ref_expr= ltlspec.bounded_semantics(fsm, formula, bound) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 0 bound = 1 # done this way to avoid the depth 1 optimisation car = Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) ref_expr= self.enc.shift_to_time(car, offset+1) \ | (self.enc.shift_to_time(car, offset) & bmcutils.loop_condition(self.enc, bound, 0)) expr = ltlspec.bounded_semantics_at_offset(fsm, formula, bound, offset)
def test_constraint_context_sigma(self): fsm = master_be_fsm() _true = Node.from_ptr(parse_ltl_spec("TRUE")) _true = bmcutils.make_nnf_boolean_wff(_true) _truen = _true.to_node() cond = Wff(parse_ltl_spec("G !(mouse = hover)"))\ .to_boolean_wff()\ .to_negation_normal_form() off_1 = 0 off_2 = 2 length = 1 # sigma1 problem = diagnosability.generate_sat_problem([], (_truen, _truen), length, _true, cond.to_node(), _truen) tm_cond = ltlspec.bounded_semantics_at_offset(fsm, cond.to_node(), length, off_1) canonical_p = tests.canonical_cnf(problem) canonical_f = tests.canonical_cnf(tm_cond) self.assertTrue(all(clause in canonical_p for clause in canonical_f)) # sigma2 problem = diagnosability.generate_sat_problem([], (_truen, _truen), length, _true, _truen, cond.to_node()) tm_cond = ltlspec.bounded_semantics_at_offset(fsm, cond.to_node(), length, off_2) canonical_p = tests.canonical_cnf(problem) canonical_f = tests.canonical_cnf(tm_cond) self.assertTrue(all(clause in canonical_p for clause in canonical_f))
def generate_sat_problem(observable_vars, formula_nodes, length, theta, sigma1, sigma2): """ Generates a SAT problem which is satisfiable iff the given `formula` is *NOT* diagnosable for the loaded model for traces of length `length`. :param observable_vars: the list of the boolean variables that are considered visible in the scope of this diagnosability test :param formula: the node (NuSMV ast representation) representing the formula whose diagnosability is under verification :param length: the maximum length of the generated traces. :param theta: the initial condition placed on the initial belief state (in the form of a :see:`pynusmv.node.Node`) :param sigma1: the shape of the traces considered relevant for the first member of the critical pair in the ongoing diagnosability test (in the form of a :see:`pynusmv.node.Node`) :param sigma2: the shape of the traces considered relevant for the second member of the critical pair in the ongoing diagnosability test (in the form of a :see:`pynusmv.node.Node`) :return: a SAT problem which is satisfiable iff the given formula is not diagnosable on the loaded model. """ fsm = master_be_fsm() offset_1 = 0 offset_2 = length + 1 problem = ( generate_path(offset_1, length) & generate_path(offset_2, length) & constraint_same_observations(observable_vars, offset_1, offset_2, length) & constraint_context_theta_initial(theta, offset_1, offset_2) & bounded_semantics_at_offset(fsm, sigma1, length, offset_1) & bounded_semantics_at_offset(fsm, sigma2, length, offset_2) & constraint_eventually_critical_pair(formula_nodes, offset_1, offset_2, length) ) return problem