def relaxed_program(prog: syntax.Program) -> syntax.Program: new_decls: List[syntax.Decl] = [d for d in prog.sorts()] actives: Dict[syntax.SortDecl, syntax.RelationDecl] = {} for sort in prog.sorts(): name = prog.scope.fresh('active_' + sort.name) r = syntax.RelationDecl(name, arity=[syntax.UninterpretedSort(sort.name)], mutable=True, derived=None, annotations=[]) actives[sort] = r new_decls.append(r) # active relations initial conditions: always true for sort in prog.sorts(): name = prog.scope.fresh(sort.name[0].upper()) expr = syntax.Forall([syntax.SortedVar(name, None)], syntax.Apply(actives[sort].name, [syntax.Id(name)])) new_decls.append(syntax.InitDecl(name=None, expr=expr)) for d in prog.decls: if isinstance(d, syntax.SortDecl): pass # already included above elif isinstance(d, syntax.RelationDecl): if d.derived_axiom is not None: expr = syntax.relativize_quantifiers(actives, d.derived_axiom) new_decls.append(syntax.RelationDecl(d.name, d.arity, d.mutable, expr, d.annotations)) else: new_decls.append(d) elif isinstance(d, syntax.ConstantDecl): new_decls.append(d) elif isinstance(d, syntax.FunctionDecl): new_decls.append(d) elif isinstance(d, syntax.AxiomDecl): new_decls.append(d) elif isinstance(d, syntax.InitDecl): new_decls.append(d) elif isinstance(d, syntax.DefinitionDecl): assert not isinstance(d.body, syntax.BlockStatement), \ "relax does not support transitions written in imperative syntax" mods, expr = d.body expr = syntax.relativize_quantifiers(actives, expr) if d.is_public_transition: guard = syntax.relativization_guard_for_binder(actives, d.binder) expr = syntax.And(guard, expr) new_decls.append(syntax.DefinitionDecl(d.is_public_transition, d.num_states, d.name, params=d.binder.vs, body=(mods, expr))) elif isinstance(d, syntax.InvariantDecl): expr = syntax.relativize_quantifiers(actives, d.expr) new_decls.append(syntax.InvariantDecl(d.name, expr=expr, is_safety=d.is_safety, is_sketch=d.is_sketch)) else: assert False, d new_decls.append(relaxation_action_def(prog, actives=actives, fresh=True)) res = syntax.Program(new_decls) res.resolve() # #sorrynotsorry return res
def p_decl_relation_derived(p: Any) -> None: 'decl : DERIVED RELATION id arity annotations COLON expr' p[0] = syntax.RelationDecl(p.slice[2], p[3].value, p[4], mutable=True, derived=p[7], annotations=p[5])
def p_decl_relation(p: Any) -> None: 'decl : mut RELATION id arity annotations' p[0] = syntax.RelationDecl(p.slice[2], p[3].value, p[4], mutable=p[1], derived=None, annotations=p[5])
def _generate_active_rels(self, scope: syntax.Scope) -> None: for sort in scope.known_sorts(): active_name = scope.fresh('active_%s' % sort.name) # TODO: is there a better way to get Sort out of SortDecl? sort_not_decl = syntax.UninterpretedSort(sort.name) typechecker.typecheck_sort(scope, sort_not_decl) active_rel = syntax.RelationDecl(active_name, arity=(sort_not_decl, ), mutable=True) self._active_rels_mapping[sort] = active_rel
def p_decl_relation_derived(p: Any) -> None: 'decl : DERIVED RELATION id arity annotations COLON expr' start_tok: Token = p.slice[1] name_tok: Token = p[3] arity_span: Optional[Span] arity: List[syntax.Sort] arity_span, arity = p[4] annots: List[syntax.Annotation] = p[5] derived_defn: syntax.Expr = p[7] p[0] = syntax.RelationDecl(name_tok.value, arity, mutable=True, derived=derived_defn, annotations=annots, span=loc_join(start_tok, derived_defn.span))
def active_rels_mapping() -> Mapping[syntax.SortDecl, syntax.RelationDecl]: # TODO: should be read from the relaxation / the program, not fixed. # TODO: duplicated from relaxed_program() actives: Dict[syntax.SortDecl, syntax.RelationDecl] = {} prog = syntax.the_program for sort in prog.sorts(): name = 'active_' + sort.name # prog.scope.fresh('active_' + sort.name) r = syntax.RelationDecl(name, arity=[syntax.UninterpretedSort(sort.name)], mutable=True, derived=None, annotations=[]) actives[sort] = r return actives
def p_decl_relation(p: Any) -> None: 'decl : mut RELATION id arity annotations' start_tok: Token is_mut: bool arity_span: Optional[Span] arity: List[syntax.Sort] start_tok, is_mut = p[1] name_tok: Token = p[3] arity_span, arity = p[4] annots: List[syntax.Annotation] = p[5] span = loc_list([start_tok, name_tok, arity_span] + [a.span for a in annots]) p[0] = syntax.RelationDecl(name_tok.value, arity, mutable=is_mut, derived=None, annotations=annots, span=span)
def sandbox(s: Solver) -> None: #################################################################################### # SANDBOX for playing with relaxed traces import pickle trns: logic.Trace = pickle.load(open("paxos_trace.p", "rb")) diff_conjunctions = relaxed_traces.derived_rels_candidates_from_trace( trns, [], 1, 3) print("num candidate relations:", len(diff_conjunctions)) for diffing_conjunction in diff_conjunctions: # print("relation:") # for conj in diffing_conjunction: # print("\t %s" % str(conj)) print(diffing_conjunction[1]) derrel_name = syntax.the_program.scope.fresh("nder") (free_vars, def_expr) = diff_conjunctions[0] def_axiom = syntax.Forall( free_vars, syntax.Iff( syntax.Apply(derrel_name, [syntax.Id(None, v.name) for v in free_vars]), # TODO: extract pattern def_expr)) derrel = syntax.RelationDecl( tok=None, name=derrel_name, arity=[syntax.safe_cast_sort(var.sort) for var in free_vars], mutable=True, derived=def_axiom, annotations=[]) # TODO: this irreversibly adds the relation to the context, wrap derrel.resolve(syntax.the_program.scope) syntax.the_program.decls.append( derrel ) # TODO: hack! because RelationDecl.resolve only adds to prog.scope s.mutable_axioms.extend([ def_axiom ]) # TODO: hack! currently we register these axioms only on solver init print("Trying derived relation:", derrel) # the new decrease_domain action incorporates restrictions that derived relations remain the same on active tuples new_decrease_domain = relaxed_traces.relaxation_action_def( syntax.the_program, fresh=False) new_prog = relaxed_traces.replace_relaxation_action( syntax.the_program, new_decrease_domain) new_prog.resolve() print(new_prog) syntax.the_program = new_prog trace_decl = next(syntax.the_program.traces()) trns2_o = bmc_trace(new_prog, trace_decl, s, lambda s, ks: logic.check_solver(s, ks, minimize=True)) assert trns2_o is not None trns2 = cast(logic.Trace, trns2_o) print(trns2) print() print( trns2.as_state(relaxed_traces.first_relax_step_idx(trns2) + 1).rel_interp[derrel]) assert not relaxed_traces.is_rel_blocking_relax( trns2, relaxed_traces.first_relax_step_idx(trns2), ([(v, str(syntax.safe_cast_sort(v.sort))) for v in free_vars], def_expr)) diff_conjunctions = list( filter( lambda candidate: relaxed_traces.is_rel_blocking_relax( trns2, relaxed_traces.first_relax_step_idx(trns2), ([(v, str(syntax.safe_cast_sort(v.sort))) for v in free_vars], def_expr)), diff_conjunctions)) print("num candidate relations:", len(diff_conjunctions)) for diffing_conjunction in diff_conjunctions: # print("relation:") # for conj in diffing_conjunction: # print("\t %s" % str(conj)) print(diffing_conjunction) print() assert False
def sandbox(s: Solver) -> None: #################################################################################### # SANDBOX for playing with relaxed traces import pickle trns: logic.Trace = pickle.load(open("paxos_trace.p", "rb")) diff_conjunctions = relaxed_traces.derived_rels_candidates_from_trace( trns, [], 2, 3) print("num candidate relations:", len(diff_conjunctions)) for diffing_conjunction in diff_conjunctions: # print("relation:") # for conj in diffing_conjunction: # print("\t %s" % str(conj)) print(diffing_conjunction[1]) derrel_name = syntax.the_program.scope.fresh("nder") (free_vars, def_expr) = diff_conjunctions[0] def_axiom = syntax.Forall( tuple(free_vars), syntax.Iff( syntax.Apply(derrel_name, tuple(syntax.Id(v.name) for v in free_vars)), # TODO: extract pattern def_expr)) derrel = syntax.RelationDecl( name=derrel_name, arity=tuple(syntax.safe_cast_sort(var.sort) for var in free_vars), mutable=True, derived=def_axiom) # TODO: this irreversibly adds the relation to the context, wrap typechecker.typecheck_statedecl(syntax.the_program.scope, derrel) syntax.the_program.decls.append( derrel ) # TODO: hack! because typecheck_statedecl only adds to prog.scope s.mutable_axioms.extend([ def_axiom ]) # TODO: hack! currently we register these axioms only on solver init print("Trying derived relation:", derrel) # the new decrease_domain action incorporates restrictions that derived relations remain the same on active tuples new_decrease_domain = relaxed_traces.relaxation_action_def( syntax.the_program, fresh=False) new_prog = relaxed_traces.replace_relaxation_action( syntax.the_program, new_decrease_domain) typechecker.typecheck_program(new_prog) print(new_prog) syntax.the_program = new_prog # TODO: recover this, making sure the candidate blocks the trace # trace_decl = next(syntax.the_program.traces()) # trns2_o = bmc_trace(new_prog, trace_decl, s, lambda s, ks: logic.check_solver(s, ks, minimize=True)) # assert trns2_o is None # migrated_trace = load_relaxed_trace_from_updr_cex(syntax.the_program, s) import pickle trns2_o = pickle.load(open("migrated_trace.p", "rb")) trns2 = cast(logic.Trace, trns2_o) print(trns2) print() assert not relaxed_traces.is_rel_blocking_relax( trns2, ([(v, str(syntax.safe_cast_sort(v.sort))) for v in free_vars], def_expr)) # for candidate in diff_conjunctions: # print("start checking") # print() # if str(candidate[1]) == ('exists v0:node. member(v0, v1) & left_round(v0, v2) ' # '& !vote(v0, v2, v3) & active_node(v0)'): # print(candidate) # assert False # resush = relaxed_traces.is_rel_blocking_relax_step( # trns2, 11, # ([(v, str(syntax.safe_cast_sort(v.sort))) for v in candidate[0]], # candidate[1])) # # res2 = trns2.as_state(0).eval(syntax.And(*[i.expr for i in syntax.the_program.inits()])) # # # resush = trns2.as_state(7).eval(syntax.And(*[i.expr for i in syntax.the_program.inits()])) # print(resush) # assert False # assert False diff_conjunctions = list( filter( lambda candidate: relaxed_traces.is_rel_blocking_relax( trns2, ([(v, str(syntax.safe_cast_sort(v.sort))) for v in candidate[0]], candidate[1])), diff_conjunctions)) print("num candidate relations:", len(diff_conjunctions)) for diffing_conjunction in diff_conjunctions: # print("relation:") # for conj in diffing_conjunction: # print("\t %s" % str(conj)) print(diffing_conjunction[1]) print() assert False
def relaxed_program(prog: syntax.Program) -> syntax.Program: new_decls: List[syntax.Decl] = [d for d in prog.sorts()] actives: Dict[syntax.SortDecl, syntax.RelationDecl] = {} for sort in prog.sorts(): name = prog.scope.fresh('active_' + sort.name) r = syntax.RelationDecl(name, arity=(syntax.UninterpretedSort(sort.name), ), mutable=True) actives[sort] = r new_decls.append(r) # active relations initial conditions: always true for sort in prog.sorts(): name = prog.scope.fresh(sort.name[0].upper()) expr = syntax.Forall((syntax.SortedVar(name, None), ), syntax.Apply(actives[sort].name, (syntax.Id(name), ))) new_decls.append(syntax.InitDecl(name=None, expr=expr)) for d in prog.decls: if isinstance(d, syntax.SortDecl): pass # already included above elif isinstance(d, syntax.RelationDecl): if d.derived_axiom is not None: expr = syntax.relativize_quantifiers(actives, d.derived_axiom) new_decls.append( syntax.RelationDecl(d.name, d.arity, d.mutable, expr, annotations=d.annotations)) else: new_decls.append(d) elif isinstance(d, syntax.ConstantDecl): new_decls.append(d) elif isinstance(d, syntax.FunctionDecl): new_decls.append(d) elif isinstance(d, syntax.AxiomDecl): new_decls.append(d) elif isinstance(d, syntax.InitDecl): new_decls.append(d) elif isinstance(d, syntax.DefinitionDecl): relativized_def = relativize_decl(d, actives, prog.scope, inline_relax_actives=False) new_decls.append(relativized_def) elif isinstance(d, syntax.InvariantDecl): expr = syntax.relativize_quantifiers(actives, d.expr) new_decls.append( syntax.InvariantDecl(d.name, expr=expr, is_safety=d.is_safety, is_sketch=d.is_sketch)) else: assert False, d new_decls.append(relaxation_action_def(prog, actives=actives, fresh=True)) res = syntax.Program(new_decls) typechecker.typecheck_program(res) # #sorrynotsorry return res