def test_decode_sat_model(self): """ Tests the behavior of BeEnc.decode_sat_model which may be used to build counter examples for complex logics """ with Configure(self, __file__, "/models/multibit.smv"): b0 = self.enc.by_name["two_bits.0"] b1 = self.enc.by_name["two_bits.1"] # Dummy expression satisfied iff Ko at time 0 and Ok at time 1 expr= b0.at_time[0].boolean_expression &\ b1.at_time[0].boolean_expression &\ -b0.at_time[1].boolean_expression &\ -b1.at_time[1].boolean_expression cnf = expr.to_cnf() solver = SatSolverFactory.create() solver += cnf # this is not required though solver.polarity(cnf, polarity=Polarity.POSITIVE) solver.solve() decoded = self.enc.decode_sat_model(solver.model) # it's true iff all bits are on, that is to day Ko at both times expect = "{0: {'two_bits': Ko}, 1: {'two_bits': Ok}}" self.assertEqual("{'two_bits': Ko}", str(decoded[0])) self.assertEqual("{'two_bits': Ok}", str(decoded[1]))
def test_next_no_loop(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("X (a <-> !b)") # bound 0 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 0) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 1) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 0 offset = 1 ref_expr= Be.false(fsm.encoding.manager) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 1 ref_expr= Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) ref_expr= fsm.encoding.shift_to_time(ref_expr, offset+1) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr))
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 test_until_with_loop(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("(a U b)") # bound 1 offset = 0 bound = 1 loop = 0 # remember: the NuSMV std apis incorporate the loop condition ! ref_expr= ltlspec.bounded_semantics_single_loop(fsm, formula, bound, loop) expr = ltlspec.bounded_semantics_with_loop_at_offset(fsm, formula, 0, bound, loop, offset) \ & bmcutils.loop_condition(self.enc, bound, loop) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 2 offset = 1 bound = 2 loop = 0 car = Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) cdr = Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) # because of the way the loop condition is encoded ! ref_expr= self.enc.shift_to_time(cdr, offset) | (self.enc.shift_to_time(car, offset) \ & self.enc.shift_to_time(cdr, offset+1)) expr = ltlspec.bounded_semantics_with_loop_at_offset(fsm, formula, 0, bound, loop, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # because loop < i, the condition must be the same as before expr = ltlspec.bounded_semantics_with_loop_at_offset(fsm, formula, 1, bound, loop, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr))
def test_globally_no_loop(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("G (a <-> !b)") # bound 0 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 0) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 1) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 0 offset = 1 ref_expr= Be.false(fsm.encoding.manager) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 1 ref_expr= Be.false(fsm.encoding.manager) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr))
def test_scalar(self): """ Tests the scalar property in BeVar """ with Configure(self, __file__, "/models/multibit.smv"): # When its a plain boolean var, nothing changes var = self.enc.by_name["__bool__"] self.assertEqual("__bool__", str(var.scalar)) # When there are multiple bits var = self.enc.by_name["two_bits.0"] self.assertEqual("two_bits", str(var.scalar))
def test_is_bit(self): """ Tests the `ìs_bit` property in BeVar """ with Configure(self, __file__, "/models/multibit.smv"): # When its a plain boolean var, nothing changes var = self.enc.by_name["__bool__"] self.assertFalse(var.is_bit) # When its not boolean but one bit is enough var = self.enc.by_name["one_bit.0"] self.assertTrue(var.is_bit) # When there are multiple bits var = self.enc.by_name["two_bits.0"] self.assertTrue(var.is_bit)
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_releases_no_loop(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("(a V b)") # bound 0 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 0) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 1) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 2 -- verification must be done by hand because the different # cnf literals mess the comparison ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 2) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 2, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 0 offset = 1 bound = 0 left = Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) right = Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) ref_expr= self.enc.shift_to_time(right, offset) & self.enc.shift_to_time(left, offset) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, bound, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 1 bound = 1 left = Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) right = Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) ref_expr= self.enc.shift_to_time(right, offset) & ( self.enc.shift_to_time(left, offset) \ | (self.enc.shift_to_time(right, 1+offset) & self.enc.shift_to_time(left, 1+offset))) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 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_until_no_loop(self): with Configure(self, __file__, "/models/flipflops.smv"): fsm = self.befsm formula = self.nnf("(a U b)") # bound 0 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 0) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 1) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, 0) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 2 -- verification must be done by hand because the different # cnf literals mess the comparison # ref_expr= ltlspec.bounded_semantics_without_loop(fsm, formula, 2) # expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 2, 0) # self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # ---- other offset ---- # bound 0 offset = 1 ref_expr= Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) ref_expr= fsm.encoding.shift_to_time(ref_expr, offset) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 0, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr)) # bound 1 offset = 1 cdr = Wff.decorate(ltlspec.cdr(formula)).to_be(fsm.encoding) car = Wff.decorate(ltlspec.car(formula)).to_be(fsm.encoding) ref_expr= fsm.encoding.shift_to_time(cdr, offset) \ | ( fsm.encoding.shift_to_time(car, offset) \ & fsm.encoding.shift_to_time(cdr, offset+1)) expr = ltlspec.bounded_semantics_without_loop_at_offset(fsm, formula, 0, 1, offset) self.assertEqual(canonical_cnf(expr), canonical_cnf(ref_expr))
def test_encode_to_bits(self): """ Tests the encode_to_bits method in BeEnc """ with Configure(self, __file__, "/models/multibit.smv"): # When its a plain boolean var name_node = get_symbol("__bool__") bits = self.enc.encode_to_bits(name_node) bits = sorted(bits, key=lambda x: str(x)) self.assertEqual("[__bool__]", str(bits)) # When its not boolean but one bit is enough name_node = get_symbol("one_bit") bits = self.enc.encode_to_bits(name_node) bits = sorted(bits, key=lambda x: str(x)) self.assertEqual("[one_bit.0]", str(bits)) # When two bits are needed name_node = get_symbol("two_bits") bits = self.enc.encode_to_bits(name_node) bits = sorted(bits, key=lambda x: str(x)) self.assertEqual("[two_bits.0, two_bits.1]", str(bits))
def test_decode_value(self): """ Tests the `ìs_bit` property in BeVar """ with Configure(self, __file__, "/models/multibit.smv"): # It must raise an exception when there is no value with self.assertRaises(ValueError): self.enc.decode_value([]) with self.assertRaises(ValueError): self.enc.decode_value(None) # When its a plain boolean var, nothing changes var = self.enc.by_name["__bool__"] self.assertTrue(self.enc.decode_value([(var, True)])) self.assertFalse(self.enc.decode_value([(var, False)])) # When its not boolean but one bit is enough var = self.enc.by_name["one_bit.0"] self.assertEqual("Ok", str(self.enc.decode_value([(var, False)]))) self.assertEqual("Ko", str(self.enc.decode_value([(var, True)]))) # When there are multiple bits b0 = self.enc.by_name["two_bits.0"] b1 = self.enc.by_name["two_bits.1"] value = [(b0, False), (b1, False)] self.assertEqual("Ok", str(self.enc.decode_value(value))) value = [(b0, False), (b1, True)] self.assertEqual("Ko", str(self.enc.decode_value(value))) value = [(b0, True), (b1, False)] self.assertEqual("DontKnow", str(self.enc.decode_value(value))) # Note: this is a 'weird' behavior although perfectly normal: it # wraps around the max value value = [(b0, True), (b1, True)] self.assertEqual("Ko", str(self.enc.decode_value(value)))
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)