예제 #1
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))
예제 #2
0
 def prev_frame_constraint(diag: Diagram) -> bool:
     pre_frame = self[j - 1].summary()
     return (
         logic.check_two_state_implication_all_transitions(
             self.solver, pre_frame, syntax.Not(diag.to_ast()), minimize=False
         ) is None and
         self.valid_in_initial_frame(syntax.Not(diag.to_ast()))
     )
예제 #3
0
def brat_next_frame(s: Solver, prev_frame: List[Expr], bound: int,
                    inits: List[Expr], safety: Expr, bad_cache: Set[Diagram],
                    minimize: bool) -> List[Expr]:
    current_frame: List[Expr] = new_frame(s, prev_frame)

    for bad_model in bad_cache:
        if logic.check_implication(s, current_frame,
                                   [syntax.Not(bad_model.to_ast())]) is None:
            continue
        current_frame.append(
            post_image_prime_consequence(
                s,
                prev_frame,
                inits,
                bad_model,
                gen_order=utils.args.generalization_order))

    while (bad_trace := bmc_upto_bound(
            s,
            safety,
            bound,
            preconds=current_frame,
            minimize=minimize,
            relaxed_semantics=utils.args.relax_backwards)) is not None:
        bad_model = Diagram(bad_trace.as_state(0))
        utils.logger.debug("Example to block: %s" % str(bad_model))
        bad_cache.add(bad_model)
        learned_clause = post_image_prime_consequence(
            s,
            prev_frame,
            inits,
            bad_model,
            gen_order=utils.args.generalization_order)
        utils.logger.info("Learned clause: %s" % str(learned_clause))
        current_frame.append(learned_clause)
예제 #4
0
    def block(
            self,
            diag_or_expr: Union[Diagram, Expr],
            j: int,
            trace: RelaxedTrace
    ) -> None:
        utils.logger.info(f'block({j})')

        def as_expr() -> Expr:
            return diag_or_expr.to_ast() if isinstance(diag_or_expr, Diagram) else diag_or_expr

        if j == 0 or (j == 1 and not self.valid_in_initial_frame(syntax.Not(as_expr()))):
            utils.logger.always_print('\n'.join(((t.name + ' ') if t is not None else '') +
                                                str(diag) for t, diag in trace))
            print('abstract counterexample: the system has no universal inductive invariant proving safety')
            if utils.args.checkpoint_out:
                self.store_frames(utils.args.checkpoint_out)
            raise AbstractCounterexample()

        while True:
            res, x = self.find_predecessor(j - 1, diag_or_expr)
            if res == unsat:
                assert x is None or isinstance(x, MySet)
                core: Optional[MySet[int]] = x
                self.augment_core_for_init(diag_or_expr, core)
                break
            assert isinstance(x, tuple), (res, x)
            trans, cti = x
            pre_diag = Diagram(cti.as_state(0))

            trace.append((trans, pre_diag))
            self.block(pre_diag, j - 1, trace)
            trace.pop()

        if isinstance(diag_or_expr, Diagram):
            diag_or_expr.minimize_from_core(core)

        def prev_frame_constraint(diag: Diagram) -> bool:
            pre_frame = self[j - 1].summary()
            return (
                logic.check_two_state_implication_all_transitions(
                    self.solver, pre_frame, syntax.Not(diag.to_ast()), minimize=False
                ) is None and
                self.valid_in_initial_frame(syntax.Not(diag.to_ast()))
            )

        if isinstance(diag_or_expr, Diagram):
            diag_or_expr.generalize(self.solver, prev_frame_constraint)
        e = syntax.Not(as_expr())
        utils.logger.info(f'block({j}) using {e}')
        self.add(e, j)
        k = j
        while k + 1 < len(self) and self.push_conjunct(k, e):
            utils.logger.info(f'and pushed to {k + 1}')
            k += 1
예제 #5
0
 def establish_safety(self) -> None:
     while bstate := self.find_something_to_block():
         self.currently_blocking = bstate
         if isinstance(bstate.state_or_expr, State):
             diag_or_expr: Union[Diagram, Expr] = Diagram(bstate.state_or_expr)
         else:
             diag_or_expr = bstate.state_or_expr
         frame_no = bstate.known_absent_until_frame + 1
         utils.logger.info(f'will block state #{bstate.id} in frame {frame_no}')
         self.block(diag_or_expr, frame_no, [(None, diag_or_expr)])
         bstate.known_absent_until_frame += 1
예제 #6
0
def oneshot_compute_inv(s: Solver, bound: int, inits: List[Expr], safety: Expr,
                        minimize: bool) -> List[Expr]:
    current_frame: List[Expr] = [syntax.TrueExpr]

    while (bad_trace := bmc_upto_bound(
            s,
            safety,
            bound,
            preconds=current_frame,
            minimize=minimize,
            relaxed_semantics=utils.args.relax_backwards)) is not None:
        bad_model = Diagram(bad_trace.as_state(0))
        learned_clause = bmc_prime_consequence(s, utils.args.forward_depth,
                                               inits, bad_model,
                                               utils.args.relax_forwards,
                                               utils.args.generalization_order)
        utils.logger.info("Learned clause: %s" % str(learned_clause))
        current_frame.append(learned_clause)
예제 #7
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def find_predecessor(
        self, pre_frame: Frame, current_phase: Phase, diag: Diagram
    ) -> Tuple[z3.CheckSatResult, Union[Optional[MySet[int]], Tuple[
            PhaseTransition, Tuple[Phase, Diagram]]]]:
        t = self.solver.get_translator(KEY_NEW, KEY_OLD)

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

        with self.solver:
            with self.solver.mark_assumptions_necessary():
                self.solver.add(diag.to_z3(t))

                transitions_into = self.automaton.transitions_to_grouped_by_src(
                    current_phase)
                for src in self._predecessor_precedence(
                        current_phase, list(transitions_into.keys())):
                    transitions = transitions_into[src]
                    assert transitions
                    utils.logger.debug(
                        "check predecessor of %s from %s by %s" %
                        (current_phase.name(), src.name(), transitions))
                    (sat_res, pre_diag) = self.find_predecessor_from_src_phase(
                        t, pre_frame, src, transitions, diag, core)
                    if sat_res == z3.unsat:
                        continue
                    return (sat_res, pre_diag)

                if utils.args.use_z3_unsat_cores:
                    assert core is not None
                    ret_core: Optional[MySet[int]] = MySet(sorted(core))
                else:
                    ret_core = None

                return (z3.unsat, ret_core)
예제 #8
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def augment_core_for_init(self, p: Phase, diag: Diagram,
                              core: Optional[MySet[int]]) -> None:
        if core is None or not utils.args.use_z3_unsat_cores:
            return

        t = self.solver.get_translator(KEY_ONE)

        with self.solver:
            for init in self.fs[0].summary_of(p):
                self.solver.add(t.translate_expr(init))

            self.solver.add(diag.to_z3(t))

            res = self.solver.check(diag.trackers)

            assert res == z3.unsat
            uc = self.solver.unsat_core()
            # if utils.logger.isEnabledFor(logging.DEBUG):
            #     utils.logger.debug('uc')
            #     utils.logger.debug(str(sorted(uc, key=lambda y: y.decl().name())))

            #     utils.logger.debug('assertions')
            #     utils.logger.debug(str(self.solver.assertions()))

            res = self.solver.check([diag.trackers[i] for i in core])
            if res == z3.unsat:
                utils.logger.debug(
                    'augment_core_for_init: existing core sufficient')
                return

            for x in sorted(uc, key=lambda y: y.decl().name()):
                assert isinstance(x, z3.ExprRef)
                core.add(int(x.decl().name()[1:]))
            if utils.logger.isEnabledFor(logging.DEBUG):
                utils.logger.debug('augment_core_for_init: new core')
                utils.logger.debug(str(sorted(core)))
예제 #9
0
 def bmc_constraint(diag: Diagram) -> bool:
     return bmc_upto_bound(s,
                           syntax.Not(diag.to_ast()),
                           bound,
                           preconds=inits,
                           relaxed_semantics=relaxed_semantics) is None
예제 #10
0
 def prev_frame_constraint(diag: Diagram) -> bool:
     return (logic.check_two_state_implication_all_transitions(
         s, prev_frame, syntax.Not(diag.to_ast()), minimize=False) is None
             and valid_in_initial_frame(s, inits, syntax.Not(
                 diag.to_ast())))
예제 #11
0
파일: updr.py 프로젝트: aatxe/mypyvy
 def valid_in_initial_frame(self, s: Solver, p: Phase,
                            diag: Diagram) -> Optional[z3.ModelRef]:
     return logic.check_implication(s, self.fs[0].summary_of(p),
                                    [syntax.Not(diag.to_ast())])
예제 #12
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def block(self,
              diag: Diagram,
              j: int,
              p: Phase,
              trace: Optional[RelaxedTrace] = None,
              safety_goal: bool = True) -> Union[Blocked, CexFound]:
        if trace is None:
            trace = []
        if j == 0 or (j == 1 and self.valid_in_initial_frame(
                self.solver, p, diag) is not None):
            if safety_goal:
                utils.logger.always_print('\n'.join(
                    ((t.pp() + ' ') if t is not None else '') + str(diag)
                    for t, diag in trace))
                print(
                    'abstract counterexample: the system has no universal inductive invariant proving safety'
                )
                # TODO: placeholder for analyzing relaxed trace
                # import relaxed_traces
                # print(relaxed_traces.diagram_trace_to_explicitly_relaxed_trace(trace, phases.phase_safety(p)))
                if utils.args.checkpoint_out:
                    self.store_frames(utils.args.checkpoint_out)
                raise AbstractCounterexample()
            else:
                if utils.logger.isEnabledFor(logging.DEBUG):
                    utils.logger.debug('failed to block diagram')
                return CexFound()

        while True:
            with utils.LogTag(utils.logger, 'block-attempt'):
                if utils.logger.isEnabledFor(logging.DEBUG):
                    utils.logger.debug('blocking diagram in frame %s' % j)
                    utils.logger.debug(str(diag))

                    self.print_frame(j - 1, lvl=logging.DEBUG)
                res, x = self.find_predecessor(self[j - 1], p, diag)
                if res == z3.unsat:
                    utils.logger.debug('no predecessor: blocked!')
                    assert x is None or isinstance(x, MySet)
                    core: Optional[MySet[int]] = x
                    self.augment_core_for_init(p, diag, core)
                    break
                assert isinstance(x, tuple), (res, x)
                trans, (pre_phase, pre_diag) = x

                trace.append((trans, pre_diag))
                ans = self.block(pre_diag, j - 1, pre_phase, trace,
                                 safety_goal)
                if not isinstance(ans, Blocked):
                    return ans
                trace.pop()

        if utils.logger.isEnabledFor(logging.DEBUG) and core is not None:
            utils.logger.debug('core %s' % core)
            utils.logger.debug('unminimized diag\n%s' % diag)

        diag.minimize_from_core(core)
        diag.generalize(self.solver, self[j - 1],
                        self.automaton.transitions_to_grouped_by_src(p),
                        p == self.automaton.init_phase(), j)

        e = syntax.Not(diag.to_ast())

        if utils.logger.isEnabledFor(logging.DEBUG):
            utils.logger.debug(
                'adding new clause to frames 0 through %d phase %s' %
                (j, p.name()))
        if utils.logger.isEnabledFor(logging.INFO):
            utils.logger.info("[%d] %s" % (j, str(e)))

        self.add(p, e, j)
        utils.logger.debug("Done blocking")

        return Blocked()
예제 #13
0
    def block(self,
              diag: Diagram,
              j: int,
              p: Phase,
              trace: Optional[List[Tuple[Optional[PhaseTransition],
                                         Union[Diagram, Expr]]]] = None,
              safety_goal: bool = True) -> Union[Blocked, CexFound]:
        if trace is None:
            trace = []
        if j == 0 or (j == 1 and self.valid_in_initial_frame(
                self.solver, p, diag) is not None):
            if safety_goal:
                utils.logger.always_print('\n'.join(
                    ((t.pp() + ' ') if t is not None else '') + str(diag)
                    for t, diag in trace))
                print('abstract counterexample')
                raise Exception('abstract counterexample')
            else:
                if utils.logger.isEnabledFor(logging.DEBUG):
                    utils.logger.debug('failed to block diagram')
                    # utils.logger.debug(str(diag))
                return CexFound()

        # print fs
        while True:
            with utils.LogTag(utils.logger, 'block-attempt'):
                if utils.logger.isEnabledFor(logging.DEBUG):
                    utils.logger.debug('blocking diagram in frame %s' % j)
                    utils.logger.debug(str(diag))

                    self.print_frame(j - 1, lvl=logging.DEBUG)
                res, x = self.find_predecessor(self[j - 1], p, diag)
                if res == z3.unsat:
                    utils.logger.debug('no predecessor: blocked!')
                    assert x is None or isinstance(x, MySet)
                    core: Optional[MySet[int]] = x
                    self.augment_core_for_init(p, diag, core)
                    break
                assert isinstance(x, tuple), (res, x)
                trans, (pre_phase, pre_diag) = x

                trace.append((trans, pre_diag))
                ans = self.block(pre_diag, j - 1, pre_phase, trace,
                                 safety_goal)
                if not isinstance(ans, Blocked):
                    return ans
                trace.pop()

        if utils.logger.isEnabledFor(logging.DEBUG) and core is not None:
            utils.logger.debug('core %s' % core)
            utils.logger.debug('unminimized diag\n%s' % diag)

        diag.minimize_from_core(core)
        diag.generalize(self.solver, self[j - 1],
                        self.automaton.transitions_to_grouped_by_src(p),
                        p == self.automaton.init_phase(), j)

        e = syntax.Not(diag.to_ast())

        if utils.logger.isEnabledFor(logging.DEBUG):
            utils.logger.debug(
                'adding new clause to frames 0 through %d phase %s' %
                (j, p.name()))
        if utils.logger.isEnabledFor(logging.INFO):
            utils.logger.info("[%d] %s" % (j, str(e)))

        self.add(p, e, j)
        utils.logger.debug("Done blocking")

        return Blocked()