Beispiel #1
0
def theorem(s: Solver) -> None:
    utils.logger.always_print('checking theorems:')

    prog = syntax.the_program
    for th in prog.theorems():
        if th.twostate:
            keys = [KEY_OLD, KEY_NEW]
        else:
            keys = [KEY_ONE]

        t = s.get_translator(*keys)

        if th.name is not None:
            msg = ' ' + th.name
        elif th.tok is not None:
            msg = ' on line %d' % th.tok.lineno
        else:
            msg = ''

        utils.logger.always_print(' theorem%s... ' % msg, end='')
        sys.stdout.flush()

        with s:
            s.add(z3.Not(t.translate_expr(th.expr)))

            logic.check_unsat([(th.tok, 'theorem%s may not hold' % msg)], s,
                              keys)
Beispiel #2
0
def check_automaton_init(s: Solver, a: AutomatonDecl) -> None:
    utils.logger.always_print('checking automaton init:')

    prog = syntax.the_program

    t = s.get_translator(KEY_ONE)

    init_decl = a.the_init()
    assert init_decl is not None  # checked by resolver
    init_phase = prog.scope.get_phase(init_decl.phase)
    assert init_phase is not None  # checked by resolver

    with s:
        for init in prog.inits():
            s.add(t.translate_expr(init.expr))

        for inv in init_phase.invs():
            with s:
                s.add(z3.Not(t.translate_expr(inv.expr)))

                if inv.tok is not None:
                    msg = ' on line %d' % inv.tok.lineno
                else:
                    msg = ''
                utils.logger.always_print('  implies phase invariant%s... ' %
                                          msg,
                                          end='')
                sys.stdout.flush()

                logic.check_unsat([
                    (inv.tok,
                     'phase invariant%s may not hold in initial state' % msg)
                ], s, [KEY_ONE])
Beispiel #3
0
def theorem(s: Solver) -> None:
    utils.logger.always_print('checking theorems:')

    prog = syntax.the_program
    for th in prog.theorems():
        if th.num_states == 2:
            num_states = 2
        elif th.num_states == 1:
            num_states = 1
        else:
            num_states = 0

        t = s.get_translator(num_states)

        if th.name is not None:
            msg = ' ' + th.name
        elif th.span is not None:
            msg = ' on line %d' % th.span[0].lineno
        else:
            msg = ''

        utils.logger.always_print(' theorem%s... ' % msg, end='')
        sys.stdout.flush()

        with s.new_frame():
            s.add(t.translate_expr(Not(th.expr)))

            logic.check_unsat([(th.span, 'theorem%s does not hold' % msg)], s,
                              num_states)
Beispiel #4
0
 def always_assert_inductive_trace(self) -> None:
     for i, f in enumerate(self.fs[:-1]):
         for c in self.fs[i + 1].summary():
             res = self.clause_implied_by_transitions_from_frame(
                 f, c, Solver())
             assert res is None, ("Non inductive trace:\n\t%s\n\t%s" %
                                  (c, f))
Beispiel #5
0
def check_automaton_edge_covering(s: Solver, a: AutomatonDecl) -> None:
    utils.logger.always_print('checking automaton edge covering:')

    prog = syntax.the_program

    t = s.get_translator(KEY_NEW, KEY_OLD)

    for phase in a.phases():
        utils.logger.always_print('  checking phase %s:' % phase.name)
        with s:
            for inv in phase.invs():
                s.add(t.translate_expr(inv.expr, old=True))

            for trans in prog.transitions():
                if any(delta.transition == trans.name and delta.precond is None for delta in phase.transitions()):
                    utils.logger.always_print('    transition %s is covered trivially.' % trans.name)
                    continue

                utils.logger.always_print('    checking transition %s is covered... ' % trans.name, end='')

                with s:
                    s.add(t.translate_transition(trans))
                    s.add(z3.And(*(z3.Not(t.translate_precond_of_transition(delta.precond, trans))
                                   for delta in phase.transitions() if trans.name == delta.transition)))

                    logic.check_unsat([(phase.tok, 'transition %s is not covered by this phase' %
                                        (trans.name, )),
                                       (trans.tok, 'this transition misses transitions from phase %s' % (phase.name,))],
                                      s, [KEY_OLD, KEY_NEW])
Beispiel #6
0
 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))
Beispiel #7
0
def check_automaton_inductiveness(s: Solver, a: AutomatonDecl) -> None:
    utils.logger.always_print('checking automaton inductiveness:')

    prog = syntax.the_program
    t = s.get_translator(KEY_NEW, KEY_OLD)

    for phase in a.phases():
        utils.logger.always_print('  checking phase %s:' % phase.name)

        with s:
            for inv in phase.invs():
                s.add(t.translate_expr(inv.expr, old=True))

            for delta in phase.transitions():
                trans = prog.scope.get_definition(delta.transition)
                assert trans is not None
                precond = delta.precond
                target = prog.scope.get_phase(
                    delta.target) if delta.target is not None else phase
                assert target is not None

                trans_pretty = '(%s, %s)' % (trans.name, str(precond) if
                                             (precond is not None) else 'true')
                utils.logger.always_print('    checking transition: %s' %
                                          trans_pretty)

                with s:
                    s.add(t.translate_transition(trans, precond=precond))
                    for inv in target.invs():
                        with s:
                            s.add(z3.Not(t.translate_expr(inv.expr)))

                            if inv.tok is not None:
                                msg = ' on line %d' % inv.tok.lineno
                            else:
                                msg = ''
                            utils.logger.always_print(
                                '      preserves invariant%s... ' % msg,
                                end='')
                            sys.stdout.flush()

                            logic.check_unsat([
                                (inv.tok,
                                 'invariant%s may not be preserved by transition %s in phase %s'
                                 % (msg, trans_pretty, phase.name)),
                                (delta.tok,
                                 'this transition may not preserve invariant%s'
                                 % (msg, ))
                            ], s, [KEY_OLD, KEY_NEW])
Beispiel #8
0
def diagram_trace_to_explicitly_relaxed_trace(trace: RelaxedTrace, safety: Sequence[syntax.InvariantDecl]) -> None:
    relaxed_prog = relaxed_program(syntax.the_program)

    with syntax.prog_context(relaxed_prog):
        s = Solver()

        end_expr = syntax.Not(syntax.And(*(invd.expr for invd in safety)))
        with syntax.the_program.scope.n_states(1):
            end_expr.resolve(syntax.the_program.scope, syntax.BoolSort)
        trace_decl = diagram_trace_to_explicitly_relaxed_trace_decl(trace, end_expr)
        with syntax.the_program.scope.n_states(1):
            trace_decl.resolve(syntax.the_program.scope)

        print(trace_decl)

        res = bmc_trace(relaxed_prog, trace_decl, s, lambda slvr, ks: logic.check_solver(slvr, ks, minimize=True))
        print(res)
        assert False
Beispiel #9
0
def translate_transition_call(s: Solver, key: str, key_old: str, c: syntax.TransitionCall) -> z3.ExprRef:
    prog = syntax.the_program
    ition = prog.scope.get_definition(c.target)
    assert ition is not None
    lator = s.get_translator(key, key_old)
    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 isinstance(a, Expr):
                bs[j] = lator.translate_expr(a)
                qs[j] = None
            else:
                assert isinstance(a, syntax.Star)
    qs1 = [q for q in qs if q is not None]
    with lator.scope.in_scope(ition.binder, bs):
        body = lator.translate_transition_body(ition)
    if len(qs1) > 0:
        return z3.Exists(qs1, body)
    else:
        return body
Beispiel #10
0
    def __init__(self, master, **kwargs):
        self.puzzleGrid = SDKGrid("")
        self.solver = Solver.Solver()

        self.master = master
        master.geometry('450x500+0+0')

        top_title_header = Frame(self.master, width=450, height=25)
        top_title_header.pack()
        top_frame = Frame(self.master, width=450, height=500)
        top_frame.pack()
        #create input (entry) widgets and assign to SDKgrid
        for x in range(9):
            for y in range(9):
                input = Entry(top_frame,
                              width=2,
                              font=("Courier", 24),
                              justify="center")
                self.puzzleGrid.get_cell_at_coords(x, y).entryBox = input
                input.grid(row=x, column=y)

        grid_to_label_spacer = Frame(width=450, height=10)
        grid_to_label_spacer.pack()
        #label for messages
        self.message = StringVar()
        self.message.set("LOAD or manually input a puzzle!")
        self.label_for_messages = Label(self.master, textvariable=self.message)
        self.label_for_messages.pack()
        #separate grid and buttons
        label_to_button_spacer = Frame(width=600, height=10)
        label_to_button_spacer.pack()
        #container for buttons
        bottom_frame = Frame(width=600, height=50)
        bottom_frame.pack()
        """Button Widgets"""
        solve_button = Button(bottom_frame,
                              text="SOLVE",
                              fg="blue",
                              command=lambda: self.solve_button())
        solve_button.pack(side=LEFT)

        step_button = Button(bottom_frame,
                             text="STEP",
                             fg="black",
                             command=lambda: self.step_button())
        step_button.pack(side=LEFT)

        populate_button = Button(bottom_frame,
                                 text="LOAD",
                                 fg="black",
                                 command=lambda: self.load())
        populate_button.pack(side=LEFT)

        save_button = Button(bottom_frame,
                             text="SAVE",
                             fg="black",
                             command=lambda: self.save())
        save_button.pack(side=LEFT)

        quit_button = Button(bottom_frame,
                             text="QUIT",
                             fg="red",
                             command=bottom_frame.quit)
        quit_button.pack(side=LEFT)
Beispiel #11
0
def bmc_trace(prog: syntax.Program,
              trace: syntax.TraceDecl,
              s: Solver,
              sat_checker: Callable[[Solver, int], Optional[logic.Trace]],
              log: bool = False) -> Optional[logic.Trace]:
    n_states = len(list(trace.transitions())) + 1
    if log:
        print('%s states' % (n_states, ))

    lator = s.get_translator(n_states)

    with s.new_frame():
        if len(trace.components) > 0 and not isinstance(
                trace.components[0], syntax.AssertDecl):
            for init in prog.inits():
                s.add(lator.translate_expr(init.expr))

        i = 0
        for c in trace.components:
            if isinstance(c, syntax.AssertDecl):
                if c.expr is None:
                    if i != 0:
                        utils.print_error_and_exit(
                            c.span,
                            'assert init is only allowed in the first state')
                    for init in prog.inits():
                        assert i == 0
                        s.add(lator.translate_expr(init.expr))
                else:
                    s.add(lator.translate_expr(New(c.expr, i)))
            else:
                te: syntax.TransitionExpr = c.transition
                if isinstance(te, syntax.AnyTransition):
                    logic.assert_any_transition(s,
                                                lator,
                                                i,
                                                allow_stutter=True)
                else:
                    l = []
                    for call in te.calls:
                        tid = z3.Bool(
                            logic.get_transition_indicator(
                                str(i), call.target))
                        l.append(tid)
                        s.add(
                            z3.Implies(
                                tid,
                                translate_transition_call(s, lator, i, call)))
                    s.add(z3.Or(*l))

                i += 1

        return sat_checker(s, n_states)
Beispiel #12
0
def bmc_trace(prog: syntax.Program,
              trace: syntax.TraceDecl,
              s: Solver,
              sat_checker: Callable[[Solver, List[str]],
                                    Optional[logic.Trace]],
              log: bool = False) -> Optional[logic.Trace]:
    n_states = len(list(trace.transitions())) + 1
    if log:
        print('%s states' % (n_states, ))

    keys = ['state%2d' % i for i in range(n_states)]

    for k in keys:
        s.get_translator(
            k)  # initialize all the keys before pushing a solver stack frame

    with s:
        lator = s.get_translator(keys[0])
        if len(trace.components) > 0 and not isinstance(
                trace.components[0], syntax.AssertDecl):
            for init in prog.inits():
                s.add(lator.translate_expr(init.expr))

        i = 0
        for c in trace.components:
            if isinstance(c, syntax.AssertDecl):
                if c.expr is None:
                    if i != 0:
                        utils.print_error_and_exit(
                            c.tok,
                            'assert init is only allowed in the first state')
                    for init in prog.inits():
                        s.add(
                            s.get_translator(keys[i]).translate_expr(
                                init.expr))
                else:
                    s.add(s.get_translator(keys[i]).translate_expr(c.expr))
            else:
                te: syntax.TransitionExpr = c.transition
                if isinstance(te, syntax.AnyTransition):
                    logic.assert_any_transition(s,
                                                str(i),
                                                keys[i + 1],
                                                keys[i],
                                                allow_stutter=True)
                else:
                    l = []
                    for call in te.calls:
                        tid = z3.Bool(
                            logic.get_transition_indicator(
                                str(i), call.target))
                        l.append(tid)
                        s.add(tid == translate_transition_call(
                            s, keys[i + 1], keys[i], call))
                    s.add(z3.Or(*l))

                i += 1

        return sat_checker(s, keys)
Beispiel #13
0
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)
def main() -> None:
    # 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?)
    resource.setrlimit(resource.RLIMIT_AS, (90 * 10**9, 90 * 10**9))

    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)

    if utils.args.print_cmdline:
        utils.logger.always_print(' '.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)
    z3.set_param('sat.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(),
                             forbid_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.')
        utils.exit(1)

    if utils.args.print_program is not None:
        if utils.args.print_program == 'str':
            to_str: Callable[[Program], str] = str
            end = '\n'
        elif utils.args.print_program == 'repr':
            to_str = repr
            end = '\n'
        elif utils.args.print_program == 'faithful':
            to_str = syntax.faithful_print_prog
            end = ''
        elif utils.args.print_program == 'without-invariants':

            def p(prog: Program) -> str:
                return syntax.faithful_print_prog(prog, skip_invariants=True)

            to_str = p
            end = ''
        else:
            assert False

        utils.logger.always_print(to_str(prog), end=end)

    pre_typecheck_error_count = utils.error_count

    typechecker.typecheck_program(prog)
    if utils.error_count > pre_typecheck_error_count:
        utils.logger.always_print('program has resolution errors.')
        utils.exit(1)

    syntax.the_program = prog

    s = Solver(use_cvc4=utils.args.cvc4)

    utils.args.main(s)

    if utils.args.ipython:
        ipython(s)

    utils.exit(1 if utils.error_count > 0 else 0)
Beispiel #15
0
def trace(s: Solver) -> None:
    prog = syntax.the_program
    if len(list(prog.traces())) > 0:
        utils.logger.always_print('finding traces:')

    for trace in prog.traces():
        n_states = len(list(trace.transitions())) + 1
        print('%s states' % (n_states,))

        keys = ['state%2d' % i for i in range(n_states)]

        for k in keys:
            s.get_translator(k)  # initialize all the keys before pushing a solver stack frame

        with s:
            lator = s.get_translator(keys[0])
            if len(trace.components) > 0 and not isinstance(trace.components[0], syntax.AssertDecl):
                for init in prog.inits():
                    s.add(lator.translate_expr(init.expr))

            i = 0
            for c in trace.components:
                if isinstance(c, syntax.AssertDecl):
                    if c.expr is None:
                        if i != 0:
                            utils.print_error_and_exit(c.tok, 'assert init is only allowed in the first state')
                        for init in prog.inits():
                            s.add(s.get_translator(keys[i]).translate_expr(init.expr))
                    else:
                        s.add(s.get_translator(keys[i]).translate_expr(c.expr))
                else:
                    te: syntax.TransitionExpr = c.transition
                    if isinstance(te, syntax.AnyTransition):
                        logic.assert_any_transition(s, str(i), keys[i + 1], keys[i], allow_stutter=True)
                    else:
                        l = []
                        for call in te.calls:
                            tid = z3.Bool(logic.get_transition_indicator(str(i), call.target))
                            l.append(tid)
                            s.add(tid == translate_transition_call(s, keys[i + 1], keys[i], call))
                        s.add(z3.Or(*l))

                    i += 1

            res = logic.check_unsat([], s, keys)
            if (res == z3.sat) != trace.sat:
                utils.print_error(trace.tok, 'trace declared %s but was %s!' % ('sat' if trace.sat else 'unsat', res))