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)
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
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]
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)
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