def assert_any_transition(s: Solver,
                          t: Z3Translator,
                          state_index: int,
                          allow_stutter: bool = False) -> None:
    prog = syntax.the_program
    uid = str(state_index)

    tids = []
    for transition in prog.transitions():
        tid = z3.Bool(get_transition_indicator(uid, transition.name))
        tids.append(tid)
        s.add(
            z3.Implies(
                tid,
                t.translate_expr(
                    New(transition.as_twostate_formula(prog.scope),
                        state_index))))

    if allow_stutter:
        tid = z3.Bool(get_transition_indicator(uid, '$stutter'))
        tids.append(tid)
        frame = syntax.And(*DefinitionDecl._frame(prog.scope, mods=()))
        s.add(z3.Implies(tid, t.translate_expr(New(frame, state_index))))

    s.add(z3.Or(*tids))
Beispiel #2
0
def check_bmc(s: Solver, safety: Expr, depth: int, preconds: Optional[Iterable[Expr]] = None,
              minimize: Optional[bool] = None) -> Optional[Trace]:
    prog = syntax.the_program

    if preconds is None:
        preconds = (init.expr for init in prog.inits())

    t = s.get_translator(depth + 1)

    with s.new_frame():
        for precond in preconds:
            s.add(t.translate_expr(precond))

        s.add(t.translate_expr(syntax.New(syntax.Not(safety), depth)))

        for i in range(depth):
            s.add(t.translate_expr(New(safety, i)))
            assert_any_transition(s, t, i, allow_stutter=False)

        res = s.check()
        if res == solver.sat:
            z3m = s.model(minimize=minimize)
            m = Z3Translator.model_to_trace(z3m, depth + 1)
            return m
        elif res == solver.unknown:
            print('unknown!')
        return None
    def model(
        self,
        assumptions: Optional[Sequence[z3.ExprRef]] = None,
        minimize: Optional[bool] = None,
        sorts_to_minimize: Optional[Iterable[z3.SortRef]] = None,
        relations_to_minimize: Optional[Iterable[z3.FuncDeclRef]] = None,
    ) -> z3.ModelRef:
        if self.cvc4_model is not None:
            return cast(z3.ModelRef, self.cvc4_model)
        assert not self.use_cvc4, 'using cvc4 but self.cvc4_model is None!'
        if minimize is None:
            minimize = utils.args.minimize_models
        if minimize:
            if sorts_to_minimize is None:
                sorts_to_minimize = [
                    Z3Translator.sort_to_z3(s)
                    for s in self.scope.sorts.values()
                    if not syntax.has_annotation(s, 'no_minimize')
                ]
            if relations_to_minimize is None:
                m = self.z3solver.model()
                ds = {str(d) for d in m.decls()}
                rels_to_minimize = []
                for r in self.scope.relations.values():
                    if r.is_derived() or syntax.has_annotation(
                            r, 'no_minimize'):
                        continue
                    if not r.mutable:
                        z3r = Z3Translator.relation_to_z3(r, None)
                        if isinstance(z3r, z3.ExprRef):
                            rels_to_minimize.append(z3r.decl())
                        else:
                            rels_to_minimize.append(z3r)
                    else:
                        # ODED: TODO: think about this, using keys here seems strange
                        for k in Z3Translator._get_keys(self.num_states):
                            z3r = Z3Translator.relation_to_z3(r, k)
                            if isinstance(z3r, z3.ExprRef):
                                z3r = z3r.decl()
                            if str(z3r) in ds:
                                rels_to_minimize.append(z3r)

            return self._minimal_model(assumptions, sorts_to_minimize,
                                       rels_to_minimize)
        else:
            return self.z3solver.model()
Beispiel #4
0
def get_cti(s: Solver, candidate: Expr) -> Optional[Tuple[Diagram, Diagram]]:
    res = logic.check_two_state_implication_all_transitions(s, [candidate],
                                                            candidate,
                                                            minimize=True)
    if res is None:
        return None
    mod = Z3Translator.model_to_trace(res[0], 2)
    return Diagram(mod.as_state(0)), Diagram(mod.as_state(1))
Beispiel #5
0
    def find_predecessor(
            self,
            j: int,
            diag_or_expr: Union[Diagram, Expr]
    ) -> Tuple[CheckSatResult, Union[Optional[MySet[int]], Tuple[DefinitionDecl, Trace]]]:
        pre_frame = self[j]
        prog = syntax.the_program
        solver = self.solver
        t = self.solver.get_translator(2)

        if utils.args.use_z3_unsat_cores:
            core: Optional[MySet[int]] = MySet()
        else:
            core = None

        def to_z3() -> z3.ExprRef:
            if isinstance(diag_or_expr, Diagram):
                return diag_or_expr.to_z3(t, new=True)
            else:
                return t.translate_expr(New(diag_or_expr))

        def trackers() -> List[z3.ExprRef]:
            if isinstance(diag_or_expr, Diagram):
                return diag_or_expr.trackers
            else:
                return []

        with solver.new_frame(), solver.mark_assumptions_necessary():
            for f in pre_frame.summary():
                solver.add(t.translate_expr(f))
            solver.add(to_z3())
            for ition in prog.transitions():
                with solver.new_frame():
                    solver.add(t.translate_expr(ition.as_twostate_formula(prog.scope)))
                    if (res := solver.check(trackers())) == sat:
                        m = Z3Translator.model_to_trace(solver.model(trackers()), 2)
                        state = m.as_state(0)
                        src = self.currently_blocking
                        assert src is not None
                        steps_from_cex = src.known_absent_until_frame + 1 - j + src.num_steps_to_bad
                        bstate = BackwardReachableState(len(self.backwards_reachable_states), state, steps_from_cex)
                        self.record_backwards_reachable_state(bstate)
                        return (sat, (ition, m))
                    elif res == unsat:
                        if utils.args.use_z3_unsat_cores and isinstance(diag_or_expr, Diagram):
                            assert core is not None
                            # carefully retrieve the unsat core before calling check again
                            uc = solver.unsat_core()
                            res = solver.check([diag_or_expr.trackers[i] for i in core])
                            if res == unsat:
                                continue
                            for x in sorted(uc, key=lambda y: y.decl().name()):
                                assert isinstance(x, z3.ExprRef)
                                core.add(int(x.decl().name()[1:]))
                    else:
                        for e in solver.assertions():
                            print(e)
                        assert False, ('z3 returned unknown', res)
Beispiel #6
0
 def to_z3(self, t: Z3Translator, new: bool = False) -> z3.ExprRef:
     # TODO: make this return Expr, not z3.ExprRef
     bs = t.bind(self.binder)
     with t.scope.in_scope(self.binder, bs):
         z3conjs = []
         self.trackers = []
         self.reverse_map: List[Tuple[_RelevantDecl, int]] = []
         i = 0
         for (d, j, c) in self.conjuncts():
             p = z3.Bool('p%d' % i)
             self.trackers.append(p)
             self.reverse_map.append((d, j))
             z3conjs.append(p == t.translate_expr(New(c) if new else c))
             i += 1
     if bs:
         return z3.Exists(bs, z3.And(*z3conjs))
     else:
         return z3.And(*z3conjs)
def translate_transition_call(s: Solver, lator: translator.Z3Translator,
                              state_index: int,
                              c: syntax.TransitionCall) -> z3.ExprRef:
    prog = syntax.the_program
    ition = prog.scope.get_definition(c.target)
    assert ition is not None
    bs = lator.bind(ition.binder)
    qs: List[Optional[z3.ExprRef]] = [b for b in bs]
    if c.args is not None:
        for j, a in enumerate(c.args):
            if not isinstance(a, syntax.Star):
                bs[j] = lator.translate_expr(New(a, state_index))
                qs[j] = None

    qs1 = [q for q in qs if q is not None]
    with lator.scope.in_scope(ition.binder, bs):
        body = lator.translate_expr(
            New(ition._framed_body(lator.scope), state_index))
    if qs1:
        return z3.Exists(qs1, body)
    else:
        return body
Beispiel #8
0
def check_solver(s: Solver, num_states: int, minimize: Optional[bool] = None) -> Optional[Trace]:
    res = s.check()
    m = None

    if res != solver.unsat:
        if res != solver.sat:
            assert res == solver.unknown
            utils.logger.always_print('unknown!')
            utils.logger.always_print('reason unknown: ' + s.reason_unknown())
            assert False, 'unexpected unknown from z3!'

        assert res == solver.sat
        m = Z3Translator.model_to_trace(s.model(minimize=minimize), num_states)

    return m
Beispiel #9
0
                                              self[min_frame_no + 1].summary(),
                                              [syntax.Not(expr)],
                                              minimize=False)
                if res is not None:
                    return bstate_min

            bstate_min.known_absent_until_frame += 1

        utils.logger.info('no existing states to block. looking for a new state.')

        f = self.fs[-1]
        if len(self.safeties) == 0 or (res := logic.check_implication(self.solver, f.summary(), self.safeties)) is None:
            utils.logger.info('frontier is safe. nothing new to block either.')
            return None

        state = Z3Translator.model_to_trace(res, 1).as_state(0)
        assert len(self) >= 2
        bstate = BackwardReachableState(len(self.backwards_reachable_states), state, 0)
        bstate.known_absent_until_frame = len(self) - 2
        self.record_backwards_reachable_state(bstate)
        return bstate

    def record_backwards_reachable_state(self, state: BackwardReachableState) -> None:
        utils.logger.info(f'discovered state #{len(self.backwards_reachable_states)}')
        utils.logger.info(str(state))
        self.backwards_reachable_states.append(state)

    def get_inductive_frame(self) -> Optional[Frame]:
        for i in range(len(self) - 1):
            if self.is_frame_inductive(i):
                return self[i + 1]