예제 #1
0
파일: updr.py 프로젝트: jrkoenig/mypyvy
    def new_frame(
            self,
            contents: Optional[Dict[Phase, Sequence[Expr]]] = None) -> None:
        if contents is None:
            contents = {}
        utils.logger.debug("new frame! %s" % len(self.fs))
        self.fs.append(Frame(self.automaton.phases(), contents))
        self.push_cache.append({p: set() for p in self.automaton.phases()})

        self.push_forward_frames()

        with utils.LogTag(utils.logger,
                          'current-frames-after-push',
                          lvl=logging.DEBUG):
            self.print_frames(lvl=logging.DEBUG)

        self.establish_safety()

        with utils.LogTag(utils.logger,
                          'current-frames-after-safety',
                          lvl=logging.DEBUG):
            self.print_frames(lvl=logging.DEBUG)

        self.simplify()

        with utils.LogTag(utils.logger,
                          'current-frames-after-simplify',
                          lvl=logging.DEBUG):
            self.print_frames(lvl=logging.DEBUG)
예제 #2
0
파일: updr.py 프로젝트: aatxe/mypyvy
 def print_frame(self, i: int, lvl: int = logging.INFO) -> None:
     f = self.fs[i]
     with utils.LogTag(utils.logger, 'frame', i=str(i)):
         for p in self.automaton.phases():
             utils.logger.log_list(lvl,
                                   ['frame %d of %s is' % (i, p.name())] +
                                   [str(x) for x in f.summary_of(p)])
예제 #3
0
파일: updr.py 프로젝트: aatxe/mypyvy
 def simplify(self) -> None:
     for i, f in enumerate(self.fs):
         for p in self.automaton.phases():
             with utils.LogTag(utils.logger, 'simplify', frame=str(i)):
                 utils.logger.debug('simplifying frame %d, pred %s' %
                                    (i, p.name()))
                 self._simplify_summary(f.summary_of(p), p)
예제 #4
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def search(self) -> Frame:
        while True:
            self.establish_safety()
            with utils.LogTag(utils.logger,
                              'current-frames-after-safety',
                              lvl=logging.DEBUG):
                self.print_frames(lvl=logging.DEBUG)

            self.simplify()
            with utils.LogTag(utils.logger,
                              'current-frames-after-simplify',
                              lvl=logging.DEBUG):
                self.print_frames(lvl=logging.DEBUG)

            self.print_status()

            n = len(self) - 1
            with utils.LogTag(utils.logger,
                              'check-frame',
                              lvl=logging.INFO,
                              n=str(n)):
                with utils.LogTag(utils.logger,
                                  'current-frames',
                                  lvl=logging.INFO):
                    self.print_frames()

                utils.logger.info('considering frame %s' % (len(self) - 1, ))

                f = self.get_inductive_frame()
                if f is not None:
                    utils.logger.always_print(
                        'frame is safe and inductive. done!')
                    for p in self.automaton.phases():
                        utils.logger.log_list(
                            utils.MyLogger.ALWAYS_PRINT,
                            ['summary of %s: ' % p.name()] +
                            [str(x) for x in f.summary_of(p)])
                    return f

                utils.logger.info(
                    'frame is safe but not inductive. starting new frame')

            self.new_frame()
예제 #5
0
파일: updr.py 프로젝트: aatxe/mypyvy
        def process_conjunct(c: Expr) -> None:
            if c in self.fs[i + 1].summary_of(p) or c in self.push_cache[i][p]:
                return

            with utils.LogTag(utils.logger,
                              'pushing-conjunct',
                              lvl=logging.DEBUG,
                              frame=str(i),
                              conj=str(c)):
                self.push_conjunct(i, c, p, frame_old_count)

            self.push_cache[i][p].add(c)
예제 #6
0
파일: updr.py 프로젝트: aatxe/mypyvy
 def always_assert_inductive_trace(self) -> None:
     for i, f in enumerate(self.fs[:-1]):
         with utils.LogTag(utils.logger,
                           'inductive-trace-assert',
                           lvl=logging.DEBUG,
                           i=str(i)):
             for p in self.automaton.phases():
                 for c in self.fs[i + 1].summary_of(p):
                     res = self.clause_implied_by_transitions_from_frame(
                         f, p, c, Solver())
                     assert res is None, (
                         "Non inductive trace:\n\t%s\n\t%s\n\t%s" %
                         (p.name(), c, f))
예제 #7
0
파일: updr.py 프로젝트: jrkoenig/mypyvy
    def search(self) -> Frame:
        init_conjuncts = [init.expr for init in syntax.the_program.inits()]
        self.new_frame({
            p: init_conjuncts
            if p == self.automaton.init_phase() else [syntax.FalseExpr]
            for p in self.automaton.phases()
        })

        self.new_frame()

        while True:
            n = len(self) - 1
            with utils.LogTag(utils.logger,
                              'check-frame',
                              lvl=logging.INFO,
                              n=str(n)):
                with utils.LogTag(utils.logger,
                                  'current-frames',
                                  lvl=logging.INFO):
                    self.print_frames()

                utils.logger.info('considering frame %s' % (len(self) - 1, ))

                f = self.get_inductive_frame()
                if f is not None:
                    utils.logger.always_print(
                        'frame is safe and inductive. done!')
                    for p in self.automaton.phases():
                        utils.logger.log_list(
                            utils.MyLogger.ALWAYS_PRINT,
                            ['summary of %s: ' % p.name()] +
                            [str(x) for x in f.summary_of(p)])
                    return f

                utils.logger.info(
                    'frame is safe but not inductive. starting new frame')
            self.new_frame()
예제 #8
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def establish_safety(self) -> None:
        self.debug_assert_inductive_trace()

        frame_no = len(self.fs) - 1

        while True:
            with utils.LogTag(utils.logger, 'establish-safety-attempt'):
                res = self._get_some_cex_to_safety()

                if res is None:
                    break

                (violating, diag) = res
                self.block(diag, frame_no, violating, [(None, diag)], True)

        self.debug_assert_inductive_trace()
예제 #9
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def push_forward_frames(self) -> None:
        self.debug_assert_inductive_trace()
        for i, f in enumerate(self.fs[:-1]):
            if ((utils.args.push_frame_zero == 'if_trivial'
                 and self.automaton.nontrivial) or
                (utils.args.push_frame_zero == 'never')) and i == 0:
                continue
            with utils.LogTag(utils.logger,
                              'pushing-frame',
                              lvl=logging.DEBUG,
                              i=str(i)):
                for p in self.automaton.phases():
                    utils.logger.debug('pushing in frame %d phase %s' %
                                       (i, p.name()))
                    self.push_phase_from_pred(i, f, p)
                    # self.debug_assert_inductive_trace()

        self.debug_assert_inductive_trace()
예제 #10
0
파일: mypyvy.py 프로젝트: jrkoenig/mypyvy
def main() -> None:
    resource.setrlimit(
        resource.RLIMIT_AS, (90 * 10**9, 90 * 10**9)
    )  # limit RAM usage to 45 GB # TODO: make this a command line argument # TODO: not sure if this is actually the right way to do this (also, what about child processes?)

    utils.args = parse_args(sys.argv[1:])

    if utils.args.log_xml:
        fmt = '%(message)s'
    elif utils.args.log_time:
        fmt = '%(asctime)s %(filename)s:%(lineno)d: %(message)s'
    else:
        fmt = '%(filename)s:%(lineno)d: %(message)s'

    if 'json' in utils.args and utils.args.json:
        utils.args.log = 'critical'

    utils.logger.setLevel(getattr(logging, utils.args.log.upper(), None))
    handler = logging.StreamHandler(stream=sys.stdout)
    handler.terminator = ''
    handler.setFormatter(MyFormatter(fmt))
    logging.root.addHandler(handler)
    # utils.logger.addHandler(handler)

    with utils.LogTag(utils.logger, 'main', lvl=logging.INFO):
        if utils.args.print_cmdline:
            with utils.LogTag(utils.logger, 'options', lvl=logging.INFO):
                utils.logger.info(' '.join([sys.executable] + sys.argv))
                utils.logger.info('Running mypyvy with the following options:')
                for k, v in sorted(vars(utils.args).items()):
                    utils.logger.info(f'    {k} = {v!r}')

        utils.logger.info('setting seed to %d' % utils.args.seed)
        z3.set_param('smt.random_seed', utils.args.seed)

        # utils.logger.info('enable z3 macro finder')
        # z3.set_param('smt.macro_finder', True)

        if utils.args.timeout is not None:
            utils.logger.info('setting z3 timeout to %s' % utils.args.timeout)
            z3.set_param('timeout', utils.args.timeout)

        pre_parse_error_count = utils.error_count

        with open(utils.args.filename) as f:
            prog = parse_program(
                f.read(),
                force_rebuild=utils.args.forbid_parser_rebuild,
                filename=utils.args.filename)

        if utils.error_count > pre_parse_error_count:
            utils.logger.always_print('program has syntax errors.')
            sys.exit(1)

        if utils.args.print_program_repr:
            utils.logger.always_print(repr(prog))
        if utils.args.print_program:
            utils.logger.always_print(str(prog))

        pre_resolve_error_count = utils.error_count

        prog.resolve()
        if utils.error_count > pre_resolve_error_count:
            utils.logger.always_print('program has resolution errors.')
            sys.exit(1)

        syntax.the_program = prog

        s = Solver()

        # initialize common keys
        s.get_translator(KEY_ONE)
        s.get_translator(KEY_NEW)
        s.get_translator(KEY_OLD)

        utils.args.main(s)

        utils.logger.info('total number of queries: %s' % s.nqueries)

        if utils.args.ipython:
            ipython(s)

    sys.exit(1 if utils.error_count > 0 else 0)
예제 #11
0
파일: updr.py 프로젝트: aatxe/mypyvy
    def find_predecessor_from_src_phase(
        self, t: syntax.Z3Translator, pre_frame: Frame, src_phase: Phase,
        transitions: Sequence[PhaseTransition], diag: Diagram,
        core: Optional[MySet[int]]
    ) -> Tuple[z3.CheckSatResult, Optional[Tuple[PhaseTransition, Tuple[
            Phase, Diagram]]]]:

        prog = syntax.the_program
        solver = self.solver
        with solver:

            for f in pre_frame.summary_of(src_phase):
                solver.add(t.translate_expr(f, old=True))

            for phase_transition in transitions:
                delta = phase_transition.transition_decl()
                trans = prog.scope.get_definition(delta.transition)
                assert trans is not None
                precond = delta.precond

                with utils.LogTag(utils.logger,
                                  'find-pred',
                                  transition=delta.transition,
                                  weight=str(
                                      phase_transition.avg_time_traversing())):
                    with solver:
                        solver.add(
                            t.translate_transition(trans, precond=precond))
                        before_check = datetime.now()
                        res = solver.check(diag.trackers)
                        phase_transition.time_spent_traversing += (
                            datetime.now() - before_check).total_seconds()
                        phase_transition.count_traversed += 1

                        if res != z3.unsat:
                            utils.logger.debug('found predecessor via %s' %
                                               trans.name)
                            m = Trace.from_z3([KEY_OLD, KEY_NEW],
                                              solver.model(diag.trackers))
                            # if utils.logger.isEnabledFor(logging.DEBUG):
                            #     utils.logger.debug(str(m))
                            self.record_state(m)
                            return (res, (phase_transition,
                                          (src_phase, m.as_diagram(i=0))))
                        elif utils.args.use_z3_unsat_cores:
                            assert core is not None
                            uc = 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(solver.assertions()))

                            res = solver.check(
                                [diag.trackers[i] for i in core])
                            if res == z3.unsat:
                                utils.logger.debug(
                                    'but existing core sufficient, skipping')
                                continue

                            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('new core')
                                utils.logger.debug(str(sorted(core)))

            return (z3.unsat, None)
예제 #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
파일: updr.py 프로젝트: aatxe/mypyvy
    def push_conjunct(self,
                      frame_no: int,
                      c: Expr,
                      p: Phase,
                      frame_old_count: Optional[int] = None) -> None:
        is_safety = c in phases.phase_safety(p)

        f = self.fs[frame_no]
        while True:
            with utils.LogTag(utils.logger,
                              'pushing-conjunct-attempt',
                              lvl=logging.DEBUG,
                              frame=str(frame_no),
                              conj=str(c)):
                utils.logger.debug('frame %s phase %s attempting to push %s' %
                                   (frame_no, p.name(), c))

                res = self.clause_implied_by_transitions_from_frame(
                    f, p, c, minimize=is_safety or utils.args.block_may_cexs)
                if res is None:
                    utils.logger.debug('frame %s phase %s managed to push %s' %
                                       (frame_no, p.name(), c))

                    if utils.args.smoke_test and utils.logger.isEnabledFor(
                            logging.DEBUG):
                        utils.logger.debug('smoke testing...')
                        # TODO: phases
                        logic.check_bmc(self.solver, c, frame_no + 1)

                    # assert self.clause_implied_by_transitions_from_frame(f, p, c) is None
                    self[frame_no + 1].strengthen(p, c)
                    self.debug_assert_inductive_trace()
                    break

                pre_phase, (m, t) = res
                mod = Trace.from_z3([KEY_OLD, KEY_NEW], m)
                self.record_state(mod)
                diag = mod.as_diagram(i=0)

                if utils.logger.isEnabledFor(logging.DEBUG):
                    utils.logger.debug(
                        'frame %s failed to immediately push %s due to '
                        'transition %s' % (frame_no, c, t.pp()))
                    # utils.logger.debug(str(mod))
                if is_safety:
                    utils.logger.debug(
                        'note: current clause is safety condition')
                    self.block(diag,
                               frame_no,
                               pre_phase, [(None, c), (t, diag)],
                               safety_goal=True)
                else:
                    if utils.args.block_may_cexs:
                        ans = self.block(diag,
                                         frame_no,
                                         pre_phase, [(None, c), (t, diag)],
                                         safety_goal=False)
                        if isinstance(ans, CexFound):
                            break
                    else:
                        break
예제 #14
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()