示例#1
0
文件: logic.py 项目: lkuper/mypyvy
 def _typecheck(self, scope: Scope) -> None:
     typechecker.pre_typecheck_binder(scope, self.binder)
     with scope.in_scope(self.binder, [v.sort for v in self.binder.vs]):
         with scope.n_states(1):
             for _, _, c in self.conjuncts():
                 typechecker.typecheck_expr(scope, c, syntax.BoolSort)
     typechecker.post_typecheck_binder(self.binder)
示例#2
0
def get_safety() -> List[Expr]:
    prog = syntax.the_program
    safety: List[Expr]
    if utils.args.safety is not None:
        the_inv: Optional[InvariantDecl] = None
        for inv in prog.invs():
            if inv.name == utils.args.safety:
                the_inv = inv
        if the_inv is not None:
            safety = [the_inv.expr]
        else:
            try:
                oldcount = utils.error_count
                e = syntax.close_free_vars(parser.parse_expr(
                    utils.args.safety))
                with prog.scope.n_states(1):
                    typechecker.typecheck_expr(prog.scope, e, syntax.BoolSort)
                assert oldcount == utils.error_count, 'errors in parsing or typechecking'
                safety = [e]
            except Exception as e:
                print(e)
                utils.print_error_and_exit(
                    None, f'--safety received string "{utils.args.safety}", '
                    'which is neither the name of an invariant/safety property '
                    'nor does it parse and typecheck as an expression')
    else:
        safety = [s.expr for s in prog.safeties()]

    return safety
示例#3
0
    def test_relativize_quantifiers(self) -> None:
        minipaxos = '''
            sort node
            sort quorum
            immutable relation member(node, quorum)
            mutable relation active_node(node)
            mutable relation active_quorum(quorum)
        '''
        prog = mypyvy.parse_program(minipaxos)
        typechecker.typecheck_program(prog)
        node = prog.scope.get_sort('node')
        assert node is not None
        quorum = prog.scope.get_sort('quorum')
        assert quorum is not None
        active_node = prog.scope.get('active_node')
        assert isinstance(active_node, syntax.RelationDecl)
        active_quorum = prog.scope.get('active_quorum')
        assert isinstance(active_quorum, syntax.RelationDecl)
        guards = {node: active_node, quorum: active_quorum}

        e = parser.parse_expr('forall Q1, Q2. exists N. member(N, Q1) & member(N, Q2)')
        typechecker.typecheck_expr(prog.scope, e, None)

        expected = parser.parse_expr('forall Q1, Q2. active_quorum(Q1) & active_quorum(Q2) -> '
                                     'exists N. active_node(N) & (member(N, Q1) & member(N, Q2))')
        with prog.scope.n_states(1):
            typechecker.typecheck_expr(prog.scope, expected, None)

        self.assertEqual(syntax.relativize_quantifiers(guards, e), expected)
def functions_total_axioms(prog: syntax.Program) -> List[Expr]:
    res = []

    for func in prog.functions():
        # TODO: generation of part of the formula duplicated from relaxation_action_def.
        # TODO: would be best to beef up the expression-generation library
        names: List[str] = []
        params = []
        for arg_sort in func.arity:
            arg_sort_decl = syntax.get_decl_from_sort(arg_sort)
            name = prog.scope.fresh(arg_sort_decl.name[0].upper(),
                                    also_avoid=names)
            names.append(name)
            params.append(syntax.SortedVar(name, arg_sort))
        ap_func = syntax.Apply(func.name,
                               tuple(syntax.Id(v.name) for v in params))

        name = prog.scope.fresh('y', also_avoid=names)

        ax = syntax.Forall(
            tuple(params),
            syntax.Exists((syntax.SortedVar(name, func.sort), ),
                          syntax.Eq(syntax.Id(name), ap_func)))
        with prog.scope.n_states(1):
            typechecker.typecheck_expr(prog.scope, ax, syntax.BoolSort)

        res.append(ax)

    return res
    def as_onestate_formula(self, index: Optional[int] = None) -> Expr:
        # TODO: move to class State, this shouldn't be here
        assert self.num_states == 1 or index is not None, \
            'to generate a onestate formula from a multi-state model, ' + \
            'you must specify which state you want'
        assert index is None or (0 <= index and index < self.num_states)

        if index is None:
            index = 0

        if index not in self.onestate_formula_cache:
            prog = syntax.the_program

            mut_rel_interps = self.rel_interps[index]
            mut_const_interps = self.const_interps[index]
            mut_func_interps = self.func_interps[index]

            vs: List[syntax.SortedVar] = []
            ineqs: Dict[SortDecl, List[Expr]] = {}
            rels: Dict[RelationDecl, List[Expr]] = {}
            consts: Dict[ConstantDecl, Expr] = {}
            funcs: Dict[FunctionDecl, List[Expr]] = {}
            for sort in self.univs:
                vs.extend(syntax.SortedVar(v, syntax.UninterpretedSort(sort.name))
                          for v in self.univs[sort])
                u = [syntax.Id(v) for v in self.univs[sort]]
                ineqs[sort] = [syntax.Neq(a, b) for a, b in combinations(u, 2)]
            for R, l in chain(mut_rel_interps.items(), self.immut_rel_interps.items()):
                rels[R] = []
                for tup, ans in l.items():
                    e: Expr = (
                        syntax.AppExpr(R.name, tuple(syntax.Id(col) for col in tup))
                        if tup else syntax.Id(R.name)
                    )
                    rels[R].append(e if ans else syntax.Not(e))
            for C, c in chain(mut_const_interps.items(), self.immut_const_interps.items()):
                consts[C] = syntax.Eq(syntax.Id(C.name), syntax.Id(c))
            for F, fl in chain(mut_func_interps.items(), self.immut_func_interps.items()):
                funcs[F] = [
                    syntax.Eq(syntax.AppExpr(F.name, tuple(syntax.Id(col) for col in tup)),
                              syntax.Id(res))
                    for tup, res in fl.items()
                ]

            # get a fresh variable, avoiding names of universe elements in vs
            fresh = prog.scope.fresh('x', [v.name for v in vs])

            e = syntax.Exists(tuple(vs), syntax.And(
                *chain(*ineqs.values(), *rels.values(), consts.values(), *funcs.values(), (
                    syntax.Forall((syntax.SortedVar(fresh,
                                                    syntax.UninterpretedSort(sort.name)),),
                                  syntax.Or(*(syntax.Eq(syntax.Id(fresh), syntax.Id(v))
                                              for v in self.univs[sort])))
                    for sort in self.univs
                ))))
            assert prog.scope is not None
            with prog.scope.n_states(1):
                typechecker.typecheck_expr(prog.scope, e, None)
            self.onestate_formula_cache[index] = e
        return self.onestate_formula_cache[index]
示例#6
0
def parse_and_typecheck_expr(input: str,
                             n_states: int = 0,
                             close_free_vars: bool = False) -> syntax.Expr:
    e = parser.parse_expr(input)
    if close_free_vars:
        e = syntax.close_free_vars(e, span=e.span)

    scope = syntax.the_program.scope
    with scope.n_states(n_states):
        typechecker.typecheck_expr(scope, e, None)
    return e
def consts_exist_axioms(prog: syntax.Program) -> List[Expr]:
    res = []

    for c in prog.constants():
        name = prog.scope.fresh('e_%s' % c.name)
        ax = syntax.Exists((syntax.SortedVar(name, c.sort), ),
                           syntax.Eq(syntax.Id(c.name), syntax.Id(name)))
        with prog.scope.n_states(1):
            typechecker.typecheck_expr(prog.scope, ax, syntax.BoolSort)
        res.append(ax)

    return res
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):
            typechecker.typecheck_expr(syntax.the_program.scope, end_expr,
                                       syntax.BoolSort)
        trace_decl = diagram_trace_to_explicitly_relaxed_trace_decl(
            trace, end_expr)
        with syntax.the_program.scope.n_states(1):
            typechecker.typecheck_tracedecl(syntax.the_program.scope,
                                            trace_decl)

        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
def is_rel_blocking_relax_step(
        trns: Trace, idx: int,
        derived_rel: Tuple[List[Tuple[syntax.SortedVar, str]], Expr]) -> bool:
    # TODO: probably can obtain the sort from the sortedvar when not using pickle
    free_vars, derived_relation_formula = derived_rel
    free_vars_active_clause = syntax.And(*(active_var(v.name, sort_name)
                                           for (v, sort_name) in free_vars))

    diffing_formula = syntax.Exists(
        tuple(v for (v, _) in free_vars),
        syntax.And(
            syntax.And(free_vars_active_clause, derived_relation_formula),
            syntax.New(
                syntax.And(free_vars_active_clause,
                           syntax.Not(derived_relation_formula)))))

    with syntax.the_program.scope.fresh_stack():
        with syntax.the_program.scope.n_states(2):
            typechecker.typecheck_expr(syntax.the_program.scope,
                                       diffing_formula, syntax.BoolSort)

    res = trns.eval(diffing_formula, idx)
    assert isinstance(res, bool)
    return cast(bool, res)
示例#10
0
def load_relaxed_trace_from_updr_cex(prog: Program, s: Solver) -> logic.Trace:
    import xml.dom.minidom  # type: ignore
    collection = xml.dom.minidom.parse(
        "paxos_derived_trace.xml").documentElement

    components: List[syntax.TraceComponent] = []

    xml_decls = reversed(collection.childNodes)
    seen_first = False

    for elm in xml_decls:
        if isinstance(elm, xml.dom.minidom.Text):  # type: ignore
            continue
        if elm.tagName == 'state':
            diagram = parser.parse_expr(elm.childNodes[0].data)
            typechecker.typecheck_expr(prog.scope, diagram, syntax.BoolSort)
            assert isinstance(
                diagram, syntax.QuantifierExpr) and diagram.quant == 'EXISTS'
            active_clauses = [
                relaxed_traces.active_var(v.name, str(v.sort))
                for v in diagram.get_vs()
            ]

            if not seen_first:
                # restrict the domain to be subdomain of the diagram's existentials
                seen_first = True
                import itertools  # type: ignore
                for sort, vars in itertools.groupby(
                        diagram.get_vs(),
                        lambda v: v.sort):  # TODO; need to sort first
                    free_var = syntax.SortedVar(
                        syntax.the_program.scope.fresh("v_%s" % str(sort)),
                        None)

                    # TODO: diagram simplification omits them from the exists somewhere
                    consts = list(
                        filter(lambda c: c.sort == sort, prog.constants()))
                    els: Sequence[Union[syntax.SortedVar, syntax.ConstantDecl]]
                    els = list(vars)
                    els += consts
                    restrict_domain = syntax.Forall(
                        (free_var, ),
                        syntax.Or(*(syntax.Eq(syntax.Id(free_var.name),
                                              syntax.Id(v.name))
                                    for v in els)))
                    active_clauses += [restrict_domain]

            diagram_active = syntax.Exists(
                diagram.get_vs(), syntax.And(diagram.body, *active_clauses))
            typechecker.typecheck_expr(prog.scope, diagram_active,
                                       syntax.BoolSort)

            components.append(syntax.AssertDecl(expr=diagram_active))
        elif elm.tagName == 'action':
            action_name = elm.childNodes[0].data.split()[0]
            tcall = syntax.TransitionCalls(
                calls=[syntax.TransitionCall(target=action_name, args=None)])
            components.append(syntax.TraceTransitionDecl(transition=tcall))
        else:
            assert False, "unknown xml tagName"

    trace_decl = syntax.TraceDecl(components=components, sat=True)
    migrated_trace = bmc_trace(
        prog,
        trace_decl,
        s,
        lambda s, ks: logic.check_solver(s, ks, minimize=True),
        log=False)

    assert migrated_trace is not None
    import pickle
    pickle.dump(migrated_trace, open("migrated_trace.p", "wb"))
    return migrated_trace