def compose_state_action(state,axioms,action, check=True): """ Compose a state and an action, returning a state """ # print "state: {}".format(state) # print "action: {}".format(action) su,sc,sp = state au,ac,ap = action sc,sp = clausify(sc),clausify(sp) if check: pre_test = and_clauses(and_clauses(sc,ap),axioms) model = small_model_clauses(pre_test) if model != None: trans = extract_pre_post_model(pre_test,model,au) post_updated = [new(s) for s in au] pre_test = exist_quant(post_updated,pre_test) raise ActionFailed(pre_test,trans) if su != None: # none means all moded ssu = set(su) # symbols already modified in state rn = dict((x,old(x)) for x in au if x not in ssu) sc = rename_clauses(sc,rn) ac = rename_clauses(ac,rn) su = list(su) union_to_list(su,au) img = forward_image(sc,axioms,action) ## print "compose: {}".format((su,img,sp)) return (su,img,sp)
def add_constraints(self,cnstrs,recompute=True): g = self fc = [c for c in cnstrs if not g.state_implies_fmla(clause_to_formula(c))] # print "fc: %s" % fc if fc: g.set_state(and_clauses(g.state,Clauses(fc)),recompute) g.constraints = and_clauses(g.constraints,Clauses(cnstrs))
def join(s1,s2,relations,op): u1,c1,p1 = s1 u2,c2,p2 = s2 c1 = and_clauses(c1,diff_frame(u1,u2,relations,op)) c2 = and_clauses(c2,diff_frame(u2,u1,relations,op)) u = updated_join(u1,u2) c = or_clauses(c1,c2) p = or_clauses(p1,p2) return (u,c,p)
def clauses_model_to_diagram(clauses1,ignore = None, implied = None,model = None,axioms=None,weaken=True,numerals=True): """ Return a diagram of a model of clauses1 or None. The function "ignore", if provided, returns true for symbols that should be ignored in the diagram. """ # print "clauses_model_to_diagram clauses1 = {}".format(clauses1) if axioms == None: axioms = true_clauses() h = model_if_none(and_clauses(clauses1,axioms),implied,model) ignore = ignore if ignore != None else lambda x: False res = model_facts(h,(lambda x: False),clauses1,upclose=True) # why not pass axioms? # print "clauses_model_to_diagram res = {}".format(res) # find representative elements # find representatives of universe elements if numerals: reps = numeral_assign(res,h) else: reps = dict() for c in used_constants_clauses(clauses1): # print "constant: {}".format(c) mc = get_model_constant(h.model,ivy_logic.Constant(c)) # print "value: {}".format(mc) if mc.rep not in reps or reps[mc.rep].rep.is_skolem() and not c.is_skolem(): reps[mc.rep] = ivy_logic.Constant(c) for s in h.sorts(): for e in h.sort_universe(s): if e.rep not in reps: reps[e.rep] = e.rep.skolem()() # print "clauses_model_to_diagram reps = {}".format(reps) # filter out clauses using universe elements without reps # res = [cls for cls in res if all(c in reps for c in used_constants_clause(cls))] # replace universe elements with their reps # print "clauses_model_to_diagram res = {}".format(res) res = substitute_constants_clauses(res,reps) # filter defined skolems # this caused a bug in the leader example. the generated diagram did not satisfy clauses1 res.fmlas = [f for f in res.fmlas if not any((x.is_skolem() and x in clauses1.defidx) for x in used_symbols_ast(f))] # print "clauses_model_to_diagram res = {}".format(res) uc = Clauses([[ivy_logic._eq_lit(ivy_logic.Variable('X',c.get_sort()),reps[c.rep]) for c in h.sort_universe(s)] for s in h.sorts()]) # print "clauses_model_to_diagram uc = {}".format(uc) # uc = true_clauses() if weaken: res = unsat_core(res,and_clauses(uc,axioms),clauses1) # implied not used here # print "clauses_model_to_diagram res = {}".format(res) # print "foo = {}".format(unsat_core(and_clauses(uc,axioms),true_clauses(),clauses1)) # filter out non-rep skolems repset = set(c.rep for e,c in reps.iteritems()) # print "clauses_model_to_diagram repset = {}".format(repset) ign = lambda x,ignore=ignore: (ignore(x) and not x in repset) res = Clauses([cl for cl in res.fmlas if not any(ign(c) for c in used_symbols_ast(cl))]) # print "clauses_model_to_diagram res = {}".format(res) return res
def satisfy(self, axioms, _get_model_clauses=None, final_cond=None): """ Produce a state sequence if the symbolic history contains one. Returns the sort universes and a sequence of states, or None if the history is vacuous. """ if _get_model_clauses is None: _get_model_clauses = small_model_clauses # print "axioms: {}".format(axioms) # A model of the post-state embeds a valuation for each time # in the history. # print "concrete state: {}".format(self.post) # print "background: {}".format(axioms) post = and_clauses(self.post,axioms) # print "bounded check {" model = _get_model_clauses(post,final_cond=final_cond) # print "} bounded check" if model == None: # print "core = {}".format(unsat_core(post,true_clauses())) return None # we reconstruct the sub-model for each state composing the # recorded renamings in reverse order. Here "renaming" maps # symbols representing a past time onto current time skolems renaming,states,maps = {},[],reversed(self.maps) while True: # ignore all symbols except those representing the given past time img = set(renaming[s] for s in renaming if not s.is_skolem()) ignore = lambda s: self.ignore(s,img,renaming) # get the sub-mode for the given past time as a formula if isinstance(final_cond,list): final_cond = or_clauses(*[fc.cond() for fc in final_cond]) all_clauses = and_clauses(post,final_cond) if final_cond != None else post clauses = clauses_model_to_clauses(all_clauses,ignore = ignore, model = model, numerals=use_numerals()) # map this formula into the past using inverse map clauses = rename_clauses(clauses,inverse_map(renaming)) # remove tautology equalities, TODO: not sure if this is correct here clauses = Clauses( [f for f in clauses.fmlas if not is_tautology_equality(f)], clauses.defs ) states.append(clauses) try: # update the inverse map by composing it with inverse # of the next renaming (in reverse order) renaming = compose_maps(next(maps),renaming) except StopIteration: break uvs = model.universes(numerals=use_numerals()) # print "uvs: {}".format(uvs) return uvs, [pure_state(clauses) for clauses in reversed(states)]
def ite(cond,s1,s2,relations,op): u1,c1,p1 = s1 u2,c2,p2 = s2 df12 = diff_frame(u1,u2,relations,op) df21 = diff_frame(u2,u1,relations,op) c1 = and_clauses(c1,df12) c2 = and_clauses(c2,df21) p1 = and_clauses(p1,df12) p2 = and_clauses(p2,df21) u = updated_join(u1,u2) c = ite_clauses(cond,[c1,c2]) p = ite_clauses(cond,[p1,p2]) return (u,c,p)
def join(s1,s2): assert isinstance(s1,SemValue) and type(s1) is type(s2) op = s1.op u1,c1,p1 = s1.comps u2,c2,p2 = s2.comps df12 = diff_frame(u1,u2,op) df21 = diff_frame(u2,u1,op) c1 = and_clauses(c1,df12) c2 = and_clauses(c2,df21) p1 = and_clauses(p1,df12) p2 = and_clauses(p2,df21) u = updated_join(u1,u2) c = or_clauses(c1,c2) p = or_clauses(p1,p2) return type(s1)(u,c,p)
def assume(self,clauses): """ Returns a new history in which the final state is constrainted to satisfy "clauses".""" # print "assume post: {}".format(self.post) # print "assume: {}".format(clauses) clauses = rename_distinct(clauses,self.post) # TODO: shouldn't be needed return History(pure_state(and_clauses(self.post,clauses)),self.maps)
def refuted_goal(goal): from z3_utils import z3_implies axioms = _ivy_interp.background_theory() premise = (and_clauses(axioms, goal.node.clauses)).to_formula() f = Not(goal.formula.to_formula()) return z3_implies(premise, f)
def try_conjectures(s): axioms = _analysis_session.analysis_state.ivy_interp.background_theory() premise = (and_clauses(axioms, s.clauses)).to_formula() return [ ('conj: {}'.format(conj), try_conjecture, conj) for conj in _analysis_session.analysis_state.ivy_interp.conjs if not z3_implies(premise, conj.to_formula()) ]
def diagram(self): from ivy_solver import clauses_model_to_diagram, get_model_clauses from ivy_transrel import is_skolem, reverse_image if not self.have_cti: if self.check_inductiveness() or len(self.g.states) != 2: return conj = self.current_conjecture post = ilu.dual_clauses(conj) if conj != None else ilu.true_clauses() pre = self.g.states[0].clauses axioms = im.module.background_theory() rev = ilu.and_clauses(reverse_image(post,axioms,self.g.states[1].update), axioms) clauses = ilu.and_clauses(pre,rev) mod = get_model_clauses(clauses) assert mod != None diag = clauses_model_to_diagram(rev,is_skolem,model=mod) self.g.states[0].clauses = diag self.view_state(self.g.states[0], reset=True) self.show_used_relations(diag,both=True)
def implies(s1,s2,axioms,relations,op): u1,c1,p1 = s1 u2,c2,p2 = s2 if u1 == None and u2 != None: return False # print "c1: {}".format(c1) # print "axioms: {}".format(axioms) # print "df: {}".format(diff_frame(u1,u2,relations,op)) c1 = and_clauses(c1,axioms,diff_frame(u1,u2,relations,op)) if isinstance(c2,Clauses): if not c2.is_universal_first_order() or not p2.is_universal_first_order(): return False c2 = and_clauses(c2,diff_frame(u2,u1,relations,op)) return clauses_imply(p1,p2) and clauses_imply(c1,c2) else: if not is_prenex_universal(c2) or not is_prenex_universal(p2): return False c2 = And(c2,clauses_to_formula(diff_frame(u2,u1,relations,op))) return clauses_imply_formula_cex(p1,p2) and clauses_imply_formula_cex(c1,c2)
def interpolant(clauses1,clauses2,axioms,interpreted): # print "interpolant clauses1={} clauses2={}".format(clauses1,clauses2) # print "axioms = {}".format(axioms) foo = and_clauses(clauses1,axioms) clauses2 = simplify_clauses(clauses2) core = unsat_core(clauses2,foo) if core == None: return None # print "core: %s" % core return core, interp_from_unsat_core(clauses2,foo,core,interpreted)
def implied_facts(premise, facts_to_check): """ Return a list of facts from facts_to_check that are implied by theory """ from z3_utils import z3_implies_batch axioms = _ivy_interp.background_theory() premise = normalize_quantifiers((and_clauses(axioms, premise)).to_formula()) facts_to_check = [f.to_formula() if type(f) is Clauses else f for f in facts_to_check] result = z3_implies_batch(premise, facts_to_check, False) return [f for f, x in zip(facts_to_check, result) if x]
def condition_update_on_fmla(update,fmla,relations): """Given an update, return an update conditioned on fmla. Maybe an "else" would be useful too :-). """ updated,if_clauses,if_pre = update else_clauses = update_frame_constraint(update,relations) if_clauses = condition_clauses(if_clauses,fmla) else_clauses = condition_clauses(else_clauses,Not(fmla)) ## print "if_clauses: %s" % if_clauses ## print "else_clauses: %s" % else_clauses return updated,(and_clauses(if_clauses,else_clauses)),if_pre
def get_diagram(goal, weaken=False): axioms = _ivy_interp.background_theory() d = ivy_solver.clauses_model_to_diagram( and_clauses(goal.node.clauses, goal.formula), is_skolem, # None, false_clauses(), axioms=axioms, weaken=weaken, ) return goal_at_arg_node(d, goal.node)
def condition_update_on_fmla(update,fmla): """Given an update, return an update conditioned on fmla. Maybe an "else" would be useful too :-). """ assert isinstance(update,SemValue) updated,if_clauses,if_pre = update.comps else_clauses = update_frame_constraint(update) if_clauses = condition_clauses(if_clauses,fmla) else_clauses = condition_clauses(else_clauses,Not(fmla)) ## print "if_clauses: %s" % if_clauses ## print "else_clauses: %s" % else_clauses return type(update)(updated,(and_clauses(if_clauses,else_clauses)),if_pre)
def compose_state_action(state,axioms,action, check=True): """ Compose a state and an action, returning a state """ # print "state: {}".format(state) # print "action: {}".format(action) su,sc,sp = state au,ac,ap = action sc,sp = clausify(sc),clausify(sp) if check: pre_test = and_clauses(and_clauses(sc,ap),axioms) if clauses_sat(pre_test): raise ActionFailed(pre_test) if su != None: # none means all moded ssu = set(su) # symbols already modified in state rn = dict((x,old(x)) for x in au if x not in ssu) sc = rename_clauses(sc,rn) ac = rename_clauses(ac,rn) su = list(su) union_to_list(su,au) img = forward_image(sc,axioms,action) ## print "compose: {}".format((su,img,sp)) return (su,img,sp)
def emit_action_gen(header,impl,name,action,classname): global indent_level caname = varname(name) upd = action.update(im.module,None) pre = tr.reverse_image(ilu.true_clauses(),ilu.true_clauses(),upd) pre_clauses = ilu.trim_clauses(pre) pre_clauses = ilu.and_clauses(pre_clauses,ilu.Clauses([df.to_constraint() for df in im.module.concepts])) pre = pre_clauses.to_formula() syms = [x for x in ilu.used_symbols_ast(pre) if x.name not in il.sig.symbols] header.append("class " + caname + "_gen : public gen {\n public:\n") for sym in syms: if not sym.name.startswith('__ts') and sym not in pre_clauses.defidx: declare_symbol(header,sym) header.append(" {}_gen();\n".format(caname)) impl.append(caname + "_gen::" + caname + "_gen(){\n"); indent_level += 1 emit_sig(impl) for sym in syms: emit_decl(impl,sym) indent(impl) impl.append('add("(assert {})");\n'.format(slv.formula_to_z3(pre).sexpr().replace('\n','\\\n'))) indent_level -= 1 impl.append("}\n"); header.append(" bool generate(" + classname + "&);\n};\n"); impl.append("bool " + caname + "_gen::generate(" + classname + "& obj) {\n push();\n") indent_level += 1 pre_used = ilu.used_symbols_ast(pre) for sym in all_state_symbols(): if sym in pre_used and sym not in pre_clauses.defidx: # skip symbols not used in constraint if slv.solver_name(sym) != None: # skip interpreted symbols global is_derived if sym not in is_derived: emit_set(impl,sym) for sym in syms: if not sym.name.startswith('__ts') and sym not in pre_clauses.defidx: emit_randomize(impl,sym) impl.append(""" bool res = solve(); if (res) { """) indent_level += 1 for sym in syms: if not sym.name.startswith('__ts') and sym not in pre_clauses.defidx: emit_eval(impl,sym) indent_level -= 2 impl.append(""" } pop(); obj.___ivy_gen = this; return res; } """)
def frame_update(update,in_scope,sig): """ Modify an update so all symbols in "in_scope" are on the update list, preserving semantics. """ updated,clauses,pre = update moded = set(updated) dfns = [] for sym in in_scope: if sym not in moded: updated.append(sym) dfns.append(frame_def(sym,new)) return (updated,and_clauses(clauses,Clauses([],dfns)),pre)
def enable_relation(self,relation): if relation.name() in self.enabled_relations: return self.enabled_relations.add(relation.name()) if use_ivy_alpha: concepts = self.relation_concepts([relation]) # # print concepts self.post.concept_spaces += concepts clauses = self.compile_concepts(concepts) # # print clauses s_add(self.solver,clauses_to_z3(clauses)) self.solver_clauses = and_clauses(self.solver.clauses,clauses)
def compose_updates(update1,axioms,update2): updated1, clauses1, pre1 = update1 updated2, clauses2, pre2 = update2 clauses2 = rename_distinct(clauses2,clauses1) pre2 = rename_distinct(pre2,clauses1) # print "clauses2 = {}".format(clauses2) us1 = set(updated1) us2 = set(updated2) mid = us1.intersection(us2) mid_ax = clauses_using_symbols(mid,axioms) used = used_symbols_clauses(and_clauses(clauses1,clauses2)) rn = UniqueRenamer('__m_',used) map1 = dict() map2 = dict() for v in updated1: map2[v] = new(v) for mv in mid: mvf = rename(mv,rn) map1[new(mv)] = mvf map2[mv] = mvf clauses1 = rename_clauses(clauses1,map1) new_clauses = and_clauses(clauses1, rename_clauses(and_clauses(clauses2,mid_ax),map2)) new_updated = list(us1.union(us2)) # print "pre1 before = {}".format(pre1) pre1 = and_clauses(pre1,diff_frame(updated1,updated2,None,new)) # keep track of post-state of assertion failure # print "pre1 = {}".format(pre1) new_pre = or_clauses(pre1,and_clauses(clauses1,rename_clauses(and_clauses(pre2,mid_ax),map2))) # print "new_pre = {}".format(new_pre) return (new_updated,new_clauses,new_pre)
def implies(s1,s2): assert isinstance(s1,SemValue) and type(s1) is type(s2) op = s1.op axioms = im.background_theory() u1,c1,p1 = s1.comps u2,c2,p2 = s2.comps if u1 == None and u2 != None: return False # print "c1: {}".format(c1) # print "axioms: {}".format(axioms) # print "df: {}".format(diff_frame(u1,u2,relations,op)) c1 = and_clauses(c1,axioms,diff_frame(u1,u2,op)) if isinstance(c2,Clauses): if not c2.is_universal_first_order() or not p2.is_universal_first_order(): return False c2 = and_clauses(c2,diff_frame(u2,u1,op)) return clauses_imply(p1,p2) and clauses_imply(c1,c2) else: if not is_prenex_universal(c2) or not is_prenex_universal(p2): return False c2 = And(c2,clauses_to_formula(diff_frame(u2,u1,op))) return clauses_imply_formula_cex(p1,p2) and clauses_imply_formula_cex(c1,c2)
def is_inductive(self, button=None): """ Check if the active conjecture implies itself at the next step TODO: this has a lot in common with check_inductiveness and is_sufficient, should refactor common parts out """ import ivy_transrel import ivy_solver from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses from random import randrange with self.ui_parent.run_context(): conj = self.get_selected_conjecture() target_conj = conj ag = self.parent.new_ag() pre = State() pre.clauses = and_clauses(conj, *self.parent.conjectures) action = im.module.actions['ext'] post = ag.execute(action, pre, None, 'ext') post.clauses = ilu.true_clauses() assert target_conj.is_universal_first_order() used_names = frozenset(x.name for x in il.sig.symbols.values()) def witness(v): c = lg.Const('@' + v.name, v.sort) assert c.name not in used_names return c clauses = dual_clauses(target_conj, witness) res = ag.bmc(post, clauses) text = '(1) ' + str(conj.to_formula()) if res is not None: self.ui_parent.text_dialog( '(1) is not relatively inductive. View counterexample?', text, command_label='View', command=lambda: self.ui_parent.add(res)) return False else: self.ui_parent.text_dialog('(1) is relatively inductive:', text, on_cancel=None) return True
def int_update(self, domain, in_scope): (updated, clauses, pre) = self.action_update(domain, in_scope) # instantiate the update axioms for u in domain.updates: updated, transrel, precond = u.get_update_axioms(updated, self) # TODO: do something with the precondition # if transrel: ## print "updated: {}".format(updated) ## print "update from axiom: %s" % transrel clauses = and_clauses(clauses, transrel) pre = or_clauses(pre, precond) ## print "update clauses: %s" % clauses res = (updated, clauses, pre) return res
def satisfy(self, axioms, _get_model_clauses=None): """ Produce a state sequence if the symbolic history contains one. Returns the sort universes and a sequence of states, or None if the history is vacuous. """ if _get_model_clauses is None: _get_model_clauses = lambda cls: get_small_model( cls, ivy_logic.sig.sorts.values(), []) # A model of the post-state embeds a valuation for each time # in the history. post = and_clauses(self.post, axioms) # print "post: {}".format(post) print "bounded check {" model = _get_model_clauses(post) print "} bounded check" if model == None: # print "core = {}".format(unsat_core(post,true_clauses())) return None # we reconstruct the sub-model for each state composing the # recorded renamings in reverse order. Here "renaming" maps # symbols representing a past time onto current time skolems renaming, states, maps = {}, [], reversed(self.maps) while True: # ignore all symbols except those representing the given past time img = set(renaming[s] for s in renaming if not s.is_skolem()) ignore = lambda s: self.ignore(s, img, renaming) # get the sub-mode for the given past time as a formula clauses = clauses_model_to_clauses(post, ignore=ignore, model=model, numerals=True) # map this formula into the past using inverse map clauses = rename_clauses(clauses, inverse_map(renaming)) # remove tautology equalities, TODO: not sure if this is correct here clauses = Clauses( [f for f in clauses.fmlas if not is_tautology_equality(f)], clauses.defs) states.append(clauses) try: # update the inverse map by composing it with inverse # of the next renaming (in reverse order) renaming = compose_maps(next(maps), renaming) except StopIteration: break return model.universes(numerals=True), [ pure_state(clauses) for clauses in reversed(states) ]
def samplePos(mod, candInv, coincide, actname): lcs = mod.labeled_conjs conjs = [Clauses([lc.formula]) for lc in lcs] fcs = [icheck.ConjChecker(c, invert=False) for c in lcs] negateci, negateCoincide = negate_clauses(candInv), negate_clauses( coincide) assert isinstance(negateci, Clauses) and isinstance( negateCoincide, Clauses), "negation causes type change" preclause = and_clauses(negateci, negateCoincide, *conjs) print "preclause: ", preclause print "not coincide: ", negateCoincide # print "<plearn> checking for action+ ", actname res = sampleUtil(mod, preclause, fcs, actname) a = raw_input('tried for pos sample') return res
def diagram(self): from ivy_solver import clauses_model_to_diagram, get_model_clauses from ivy_transrel import is_skolem, reverse_image if not self.have_cti: if self.check_inductiveness() or len(self.g.states) != 2: return conj = self.current_conjecture post = ilu.dual_clauses(conj) if conj != None else ilu.true_clauses() pre = self.g.states[0].clauses axioms = im.module.background_theory() uc = universe_constraint(self.g.states[0]) axioms_uc = ilu.and_clauses(axioms, uc) # rev = ilu.and_clauses(reverse_image(post,axioms,self.g.states[1].update), axioms) rev = reverse_image(post, axioms, self.g.states[1].update) clauses = ilu.and_clauses(ilu.and_clauses(pre, rev), axioms_uc) mod = get_model_clauses(clauses) assert mod != None diag = clauses_model_to_diagram(rev, is_skolem, model=mod, axioms=axioms) self.view_state(self.g.states[0], clauses=diag, reset=True) self.show_used_relations(diag, both=True) self.current_concept_graph.gather_facts()
def make_check_art(act_name=None, precond=[]): action = act.env_action(act_name) ag = art.AnalysisGraph() pre = itp.State() pre.clauses = lut.and_clauses(*precond) pre.clauses.annot = act.EmptyAnnotation() with itp.EvalContext(check=False): # don't check safety post = ag.execute(action, pre) post.clauses = lut.true_clauses() fail = itp.State(expr=itp.fail_expr(post.expr)) return ag, post, fail
def minimize_conjecture(self, button=None, bound=None): import ivy_transrel import ivy_solver from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses, used_symbols_clauses, negate from ivy_solver import unsat_core from logic_util import free_variables, substitute if self.bmc_conjecture(bound=bound): # found a BMC counter-example return with self.ui_parent.run_context(): step_action = im.module.actions['ext'] n_steps = self.current_bound ag = self.parent.new_ag() with ag.context as ac: post = ac.new_state(ag.init_cond) if 'initialize' in im.module.actions: init_action = im.module.actions['initialize'] post = ag.execute(init_action, None, None, 'initialize') for n in range(n_steps): post = ag.execute(step_action, None, None, 'ext') axioms = im.module.background_theory() post_clauses = and_clauses(post.clauses, axioms) used_names = (frozenset(x.name for x in il.sig.symbols.values()) | frozenset( x.name for x in used_symbols_clauses(post_clauses))) facts = self.get_active_facts() assert not any(c.is_skolem() and c.name in used_names for c in lu.used_constants(*facts)) core = unsat_core(Clauses(facts), post_clauses) if core is None: core = Clauses([]) ## can happen if we are proving true # assert core is not None, "bmc_conjecture returned False but unsat core is None" core_formulas = frozenset(core.fmlas) self.set_facts([fact for fact in facts if fact in core_formulas]) self.highlight_selected_facts() self.ui_parent.text_dialog( "BMC found the following possible conjecture:", str(self.get_selected_conjecture()))
def minimize_conjecture(self, button=None, bound=None): import ivy_transrel import ivy_solver from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses, used_symbols_clauses, negate from ivy_solver import unsat_core from logic_util import free_variables, substitute if self.bmc_conjecture(bound=bound): # found a BMC counter-example return with self.ui_parent.run_context(): step_action = im.module.actions['ext'] n_steps = self.current_bound ag = self.parent.new_ag() with ag.context as ac: post = ac.new_state(ag.init_cond) if 'initialize' in im.module.actions: init_action = im.module.actions['initialize'] post = ag.execute(init_action, None, None, 'initialize') for n in range(n_steps): post = ag.execute(step_action, None, None, 'ext') axioms = im.module.background_theory() post_clauses = and_clauses(post.clauses, axioms) used_names = ( frozenset(x.name for x in il.sig.symbols.values()) | frozenset(x.name for x in used_symbols_clauses(post_clauses)) ) facts = self.get_active_facts() assert not any( c.is_skolem() and c.name in used_names for c in lu.used_constants(*facts) ) core = unsat_core(Clauses(facts), post_clauses) if core is None: core = Clauses([]) ## can happen if we are proving true # assert core is not None, "bmc_conjecture returned False but unsat core is None" core_formulas = frozenset(core.fmlas) self.set_facts([fact for fact in facts if fact in core_formulas]) self.highlight_selected_facts() self.ui_parent.text_dialog("BMC found the following possible conjecture:", str(self.get_selected_conjecture()))
def is_sufficient(self, button=None): """ Check if the active conjecture is sufficient to imply the current CTI conjecture at the next step TODO: this has a lot in common with check_inductiveness, should refactor common parts out """ import ivy_transrel import ivy_solver from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses from random import randrange with self.ui_parent.run_context(): conj = self.get_selected_conjecture() target_conj = self.parent.current_conjecture ag = self.parent.new_ag() pre = State() pre.clauses = and_clauses(conj, *self.parent.conjectures) action = im.module.actions['ext'] post = ag.execute(action, pre, None, 'ext') post.clauses = ilu.true_clauses() assert target_conj.is_universal_first_order() used_names = frozenset(x.name for x in il.sig.symbols.values()) def witness(v): c = lg.Const('@' + v.name, v.sort) assert c.name not in used_names return c clauses = dual_clauses(target_conj, witness) res = ag.bmc(post, clauses) text = '(1) ' + str(conj.to_formula()) + '\n(2) ' + str(target_conj.to_formula()) if res is not None: self.ui_parent.text_dialog('(1) does not imply (2) at the next time. View counterexample?', text,command_label='View',command = lambda: self.ui_parent.add(res)) return False else: self.ui_parent.text_dialog('(1) implies (2) at the next time:',text,on_cancel=None) return True
def compose_updates(update1, axioms, update2): updated1, clauses1, pre1 = update1 updated2, clauses2, pre2 = update2 clauses2 = rename_distinct(clauses2, clauses1) pre2 = rename_distinct(pre2, clauses1) # print "clauses2 = {}".format(clauses2) us1 = set(updated1) us2 = set(updated2) mid = us1.intersection(us2) mid_ax = clauses_using_symbols(mid, axioms) used = used_symbols_clauses(and_clauses(clauses1, clauses2)) used.update(symbols_clauses(pre1)) used.update(symbols_clauses(pre2)) rn = UniqueRenamer('__m_', used) map1 = dict() map2 = dict() for v in updated1: map2[v] = new(v) for mv in mid: mvf = rename(mv, rn) map1[new(mv)] = mvf map2[mv] = mvf # iu.dbg('clauses1') # iu.dbg('clauses1.annot') clauses1 = rename_clauses(clauses1, map1) annot_op = lambda x, y: x.compose( y) if x is not None and y is not None else None new_clauses = and_clauses(clauses1, rename_clauses(and_clauses(clauses2, mid_ax), map2), annot_op=annot_op) new_updated = list(us1.union(us2)) # print "pre1 before = {}".format(pre1) # iu.dbg('pre1.annot') # iu.dbg('pre1') pre1 = and_clauses(pre1, diff_frame( updated1, updated2, new, axioms)) # keep track of post-state of assertion failure # print "pre1 = {}".format(pre1) temp = and_clauses(clauses1, rename_clauses(and_clauses(pre2, mid_ax), map2), annot_op=my_annot_op) # iu.dbg('temp.annot') new_pre = or_clauses(pre1, temp) # iu.dbg('new_pre.annot') # print "new_pre = {}".format(new_pre) # iu.dbg('new_clauses') # iu.dbg('new_clauses.annot') return (new_updated, new_clauses, new_pre)
def check_final_cond(ag, post, final_cond, rels_to_min=[], shrink=False, handler_class=None): history = ag.get_history(post) axioms = im.module.background_theory() clauses = history.post clauses = lut.and_clauses(clauses, axioms) assert all(x is not None for x in history.actions) # work around a bug in ivy_interp actions = [ im.module.actions[a] if isinstance(a, str) else a for a in history.actions ] action = act.Sequence(*actions) return check_vc(clauses, action, final_cond, rels_to_min, shrink, handler_class)
def get_solver_clauses(self): # expr = self.state_as_z3_expr if use_ivy_alpha: d = ProgressiveDomain(verbose=True) self.post = d sorts = sorted(set(n.sort for n in self.all_nodes)) concepts = [] for s in sorts: nconcepts = [n.to_concept_space() for n in self.all_nodes] nconcepts.append((node_concept(s,'X').atom, SumSpace([NamedSpace(Literal(1,x)) for x,y in nconcepts]))) nconcepts.append((xtra_concept(s,'X','Y').atom,SumSpace([x for n in self.all_nodes for x in n.extra_concepts()]))) concepts += nconcepts concepts = concepts + self.relation_concepts([r for r in self.relations if r.name() in self.enabled_relations]) d.concept_spaces = concepts # # print "concepts: %s" % concepts d.post_init(self.state,[],{},[]) clauses = self.compile_concepts(concepts) # # print "clauses: %s" % clauses else: clauses = self.state # print "graph solver clauses = {}".format(clauses) s_add(self.solver,clauses_to_z3(clauses)) self.solver_clauses = and_clauses(self.solver_clauses,clauses)
def check_vc(clauses, action, final_cond=None, rels_to_min=[], shrink=False, handler_class=None): model = slv.get_small_model(clauses, lg.uninterpreted_sorts(), rels_to_min, final_cond=final_cond, shrink=shrink) if model is not None: failed = ([] if final_cond is None else [final_cond] if not isinstance(final_cond, list) else [c.cond() for c in ffcs if c.failed]) mclauses = lut.and_clauses(*([clauses] + failed)) vocab = lut.used_symbols_clauses(mclauses) handler = (handler_class(mclauses, model, vocab) if handler_class is not None else Trace(mclauses, model, vocab)) act.match_annotation(action, clauses.annot, handler) handler.end() return handler return None
def isValid(self): ''' Checks if the current instance is a valid samplePoint. i.e. for negative sample it checks if the samplePoint satisfies negation of current invariant (fcs) in post state Assumptions : safety Condition and Candidate Inv and Coincide clause is Universally Quantified. ''' global module, candInv, coincide if self.label == '0': # nagative sample fcs = [icheck.ConjChecker(c) for c in module.labeled_conjs] # inverts the fmla fmlas = [ fc.cond().fmlas for fc in fcs ] # fc.cond().fmlas gives a list of ivy predicate logic object. else: # positive sample # return True # It will cause repeatation of some positive samples, but it will not affect the correctness of algorithm # comment the above return stmt to check validity of positive samples negateci, negateCoincide = negate_clauses(candInv), negate_clauses( coincide) condition = and_clauses(negateci, negateCoincide) fmlas = [condition.fmlas] # assert len(fmlas) == 1, "" for fmla in fmlas: # requires satisfying atleast one fmla, as they are in disjunction isfmlatrue = True for pred in fmla: ret = self.solveIvyfmla(pred) assert isinstance( ret, logic.Const), "return value is not a Const object" assert isinstance( ret.sort, BooleanSort), "return is not a boolean formla" assert ret.name in ["0", "1" ], "return value is not in correct format" # print "<plearn> pred: {} \t\t result: {}".format(pred, ret.name) if ret.name == "0": isfmlatrue = False break if isfmlatrue: return True return False
def compose_updates(update1,axioms,update2): updated1, clauses1, pre1 = update1 updated2, clauses2, pre2 = update2 clauses2 = rename_distinct(clauses2,clauses1) pre2 = rename_distinct(pre2,clauses1) # print "clauses2 = {}".format(clauses2) us1 = set(updated1) us2 = set(updated2) mid = us1.intersection(us2) mid_ax = clauses_using_symbols(mid,axioms) used = used_symbols_clauses(and_clauses(clauses1,clauses2)) rn = UniqueRenamer('__m_',used) map1 = dict() map2 = dict() for v in updated1: map2[v] = new(v) for mv in mid: mvf = rename(mv,rn) map1[new(mv)] = mvf map2[mv] = mvf # iu.dbg('clauses1') # iu.dbg('clauses1.annot') clauses1 = rename_clauses(clauses1,map1) annot_op = lambda x,y: x.compose(y) if x is not None and y is not None else None new_clauses = and_clauses(clauses1, rename_clauses(and_clauses(clauses2,mid_ax),map2),annot_op=annot_op) new_updated = list(us1.union(us2)) # print "pre1 before = {}".format(pre1) # iu.dbg('pre1.annot') # iu.dbg('pre1') pre1 = and_clauses(pre1,diff_frame(updated1,updated2,None,new)) # keep track of post-state of assertion failure # print "pre1 = {}".format(pre1) temp = and_clauses(clauses1,rename_clauses(and_clauses(pre2,mid_ax),map2),annot_op=my_annot_op) # iu.dbg('temp.annot') new_pre = or_clauses(pre1,temp) # iu.dbg('new_pre.annot') # print "new_pre = {}".format(new_pre) # iu.dbg('new_clauses') # iu.dbg('new_clauses.annot') return (new_updated,new_clauses,new_pre)
def compose_updates(update1, update2): assert isinstance(update1, SemActionValue) and type(update1) is type(update2) axioms = im.background_theory() updated1, clauses1, pre1 = update1.comps updated2, clauses2, pre2 = update2.comps clauses2 = rename_distinct(clauses2, clauses1) pre2 = rename_distinct(pre2, clauses1) # print "clauses2 = {}".format(clauses2) us1 = set(updated1) us2 = set(updated2) mid = us1.intersection(us2) mid_ax = clauses_using_symbols(mid, axioms) used = used_symbols_clauses(and_clauses(clauses1, clauses2)) rn = UniqueRenamer('__m_', used) map1 = dict() map2 = dict() for v in updated1: map2[v] = new(v) for mv in mid: mvf = rename(mv, rn) map1[new(mv)] = mvf map2[mv] = mvf clauses1 = rename_clauses(clauses1, map1) new_clauses = and_clauses( clauses1, rename_clauses(and_clauses(clauses2, mid_ax), map2)) new_updated = list(us1.union(us2)) # print "pre1 before = {}".format(pre1) pre1 = and_clauses( pre1, diff_frame(updated1, updated2, new)) # keep track of post-state of assertion failure # print "pre1 = {}".format(pre1) new_pre = or_clauses( pre1, and_clauses(clauses1, rename_clauses(and_clauses(pre2, mid_ax), map2))) # print "new_pre = {}".format(new_pre) return SemActionValue(new_updated, new_clauses, new_pre)
def action_update(self,domain,pvars): lhs,rhs = self.args n = lhs.rep # Handle the hierarchical case if n in domain.hierarchy: asgns = [postfix_atoms_ast(self,Atom(x,[])) for x in domain.hierarchy[n]] res = unzip_append([asgn.action_update(domain,pvars) for asgn in asgns]) return res # If the lhs application is partial, make it total by adding parameters xtra = len(lhs.rep.sort.dom) - len(lhs.args) if xtra < 0: raise IvyError(self,"too many parameters in assignment to " + lhs.rep) if xtra > 0: extend = sym_placeholders(lhs.rep)[-xtra:] extend = variables_distinct_list_ast(extend,self) # get unused variables lhs = add_parameters_ast(lhs,extend) # Assignment of individual to a boolean is a special case if is_individual_ast(rhs) and not is_individual_ast(lhs): rhs = eq_atom(extend[-1],add_parameters_ast(rhs,extend[0:-1])) else: rhs = add_parameters_ast(rhs,extend) lhs_vars = used_variables_ast(lhs) if any(v not in lhs_vars for v in used_variables_ast(rhs)): print self raise IvyError(self,"multiply assigned: {}".format(lhs.rep)) type_check(domain,rhs) if is_individual_ast(lhs) != is_individual_ast(rhs): # print type(lhs.rep) # print str(lhs.rep) # print type(lhs.rep.sort) # print "lhs: %s: %s" % (lhs,type(lhs)) # print "rhs: %s: %s" % (rhs,type(rhs)) raise IvyError(self,"sort mismatch in assignment to {}".format(lhs.rep)) # For a destructor assignment, we actually mutate the first argument if n.name in ivy_module.module.destructor_sorts: mut = lhs.args[0] rest = list(lhs.args[1:]) mut_n = mut.rep nondet = mut_n.suffix("_nd").skolem() new_clauses = mk_assign_clauses(mut_n,nondet(*sym_placeholders(mut_n))) fmlas = [] nondet_lhs = lhs.rep(*([nondet(*mut.args)]+rest)) fmlas.append(equiv_ast(nondet_lhs,rhs)) vs = sym_placeholders(n) dlhs = n(*([nondet(*mut.args)] + vs[1:])) drhs = n(*([mut] + vs[1:])) eqs = [eq_atom(v,a) for (v,a) in zip(vs,lhs.args)[1:] if not isinstance(a,Variable)] if eqs: fmlas.append(Or(And(*eqs),equiv_ast(dlhs,drhs))) for destr in ivy_module.module.sort_destructors[mut.sort.name]: if destr != n: phs = sym_placeholders(destr) a1 = [nondet(*mut.args)] + phs[1:] a2 = [mut] + phs[1:] fmlas.append(eq_atom(destr(*a1),destr(*a2))) new_clauses = and_clauses(new_clauses,Clauses(fmlas)) return ([mut_n], new_clauses, false_clauses()) new_clauses = mk_assign_clauses(lhs,rhs) # print "assign new_clauses = {}".format(new_clauses) return ([n], new_clauses, false_clauses())
def constrain_state(upd, fmla): assert isinstance(upd, SemStateValue) return SemStateValue(upd.modset, and_clauses(upd.trans, formula_to_clauses(fmla)), upd.fail)
def interactive_updr(): frames = ta._ivy_ag.states if len(frames) != 1: raise InteractionError( "Interactive UPDR can only be started when the ARG " + "contains nothing but the initial state.") bad_states = negate_clauses(ta.get_safety_property()) action = ta.get_big_action() ta._ivy_ag.actions[repr(action)] = action init_frame = last_frame = frames[0] # TODO: test conjecture in initial while True: # the property is true in all frames and all "clauses" are pushed # the goal stack is empty # check if we found an infuctive invariant for i in range(len(frames) - 1): if t.check_cover(frames[i + 1], frames[i]): ta.step(msg="Inductive invariant found at frame {}".format(i), i=i) # return True # add new frame last_frame = ta.arg_add_action_node(last_frame, action, None) ta.push_goal(ta.goal_at_arg_node(bad_states, last_frame)) ta.step(msg="Added new frame") # push facts to last frame t.recalculate_facts(last_frame, ta.arg_get_conjuncts(ta.arg_get_pred(last_frame))) while True: current_goal = ta.top_goal() if current_goal is None: # goal stack is empty break if t.remove_if_refuted(current_goal): continue if current_goal.node == init_frame: # no invariant print "No Invariant!" # return False dg = ta.get_diagram(current_goal, False) options = OrderedDict() for c in simplify_clauses(dg.formula).conjuncts(): options[str(c)] = c user_selection = (yield UserSelectMultiple( options=options, title="Generalize Diagram", prompt="Choose which literals to take as the refutation goal", default=options.values())) assert user_selection is not None ug = ta.goal_at_arg_node(Clauses(list(user_selection)), current_goal.node) ta.push_goal(ug) ta.step(msg='Pushed user selected goal', ug=ug) goal = ta.top_goal() preds, action = ta.arg_get_preds_action(goal.node) assert action != 'join' assert len(preds) == 1 pred = preds[0] axioms = ta._ivy_interp.background_theory() theory = and_clauses( ivy_transrel.forward_image(pred.clauses, axioms, action.update(ta._ivy_interp, None)), axioms) goal_clauses = simplify_clauses(goal.formula) assert len(goal_clauses.defs) == 0 s = z3.Solver() s.add(clauses_to_z3(theory)) s.add(clauses_to_z3(goal_clauses)) is_sat = s.check() if is_sat == z3.sat: bi = ta.backward_image(goal.formula, action) x, y = False, ta.goal_at_arg_node(bi, pred) elif is_sat == z3.unsat: user_selection, user_is_sat = yield UserSelectCore( theory=theory, constrains=goal_clauses.fmlas, title="Refinement", prompt="Choose the literals to use", ) assert user_is_sat is False core = Clauses(user_selection) x, y = True, ivy_transrel.interp_from_unsat_core( goal_clauses, theory, core, None) else: assert False, is_sat t.custom_refine_or_reverse(goal, x, y, False) # propagate phase for i in range(1, len(frames)): facts_to_check = (set(ta.arg_get_conjuncts(frames[i - 1])) - set(ta.arg_get_conjuncts(frames[i]))) t.recalculate_facts(frames[i], list(facts_to_check))
def constrain_state(upd, fmla): return (upd[0], and_clauses(upd[1], formula_to_clauses(fmla)), upd[2])
def conjoin(clauses1, clauses2, annot_op=None): """ Conjoin clause sets, taking into account skolems """ return and_clauses(clauses1, rename_distinct(clauses2, clauses1), annot_op=annot_op)
def check_inductiveness(self, button=None): import ivy_transrel from ivy_solver import get_small_model from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses from random import randrange with self.ui_parent.run_context(): ag = self.new_ag() pre = State() pre.clauses = and_clauses(*self.conjectures) action = im.module.actions['ext'] with EvalContext(check=False): # don't check safety post = ag.execute(action, pre, None, 'ext') post.clauses = ilu.true_clauses() to_test = list(self.conjectures) + [None] # None = check safety while len(to_test) > 0: # choose randomly, so the user can get another result by # clicking again conj = to_test.pop(randrange(len(to_test))) assert conj == None or conj.is_universal_first_order() used_names = frozenset(x.name for x in il.sig.symbols.values()) def witness(v): c = lg.Const('@' + v.name, v.sort) assert c.name not in used_names return c # TODO: this is still a bit hacky, and without nice error reporting if self.relations_to_minimize.value == 'relations to minimize': self.relations_to_minimize.value = ' '.join(sorted( k for k, v in il.sig.symbols.iteritems() if (type(v.sort) is lg.FunctionSort and v.sort.range == lg.Boolean and v.name not in self.transitive_relations and '.' not in v.name ) )) if conj == None: # check safety clauses = ilu.true_clauses() rels_to_min = [il.sig.symbols[x] for x in self.relations_to_minimize.value.split()] else: clauses = dual_clauses(conj, witness) history = ag.get_history(post) rels_to_min = [ # TODO: this is still a bit hacky, and without nice error reporting history.maps[0].get(relation, relation) for x in self.relations_to_minimize.value.split() for relation in [il.sig.symbols[x]] ], _get_model_clauses = lambda clauses, final_cond=False: get_small_model( clauses, sorted(il.sig.sorts.values()), rels_to_min, final_cond = final_cond ) if conj == None: print "check safety" res = ag.check_bounded_safety(post, _get_model_clauses) else: res = ag.bmc(post, clauses, None, None, _get_model_clauses) if res is not None: self.current_conjecture = conj assert len(res.states) == 2 # self.set_states(res.states[0], res.states[1]) # self.cti = self.ui_parent.add(res) self.g = res self.rebuild() self.view_state(self.g.states[0], reset=True) self.show_used_relations(clauses) #self.post_graph.selected = self.get_relevant_elements(self.post_state[2], clauses) if conj == None: self.ui_parent.ok_dialog('An assertion failed. A failing state is displayed. You can decompose\nthe failing action observe the failing execution. ') else: self.ui_parent.text_dialog('The following conjecture is not relatively inductive:', str(conj.to_formula()),on_cancel=None) self.have_cti = True return False # self.set_states(False, False) self.ui_parent.text_dialog('Inductive invariant found:', '\n'.join(str(conj) for conj in self.conjectures)) self.have_cti = False return True
def arg_add_facts(node, *facts): """ Add facts to arg node """ for f in facts: node.clauses = and_clauses(node.clauses, f)
def get_formula(self, clauses): cl = lut.and_clauses(clauses) f = cl.to_formula() return f
def bmc_conjecture(self, button=None, bound=None, conjecture=None, verbose=False, tell_unsat=True): import ivy_transrel import ivy_solver from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses # get the bound, if not specified if bound is None: iv = self.current_bound if hasattr(self, 'current_bound') else None c = lambda b: self.bmc_conjecture(button=button, bound=b, conjecture=conjecture, verbose=verbose, tell_unsat=tell_unsat) self.ui_parent.int_dialog('Number of steps to check:', command=c, minval=0, initval=iv) return with self.ui_parent.run_context(): step_action = ia.env_action(None) n_steps = bound self.current_bound = bound conj = conjecture if conj is None: conj = and_clauses(*self.conjectures) assert conj.is_universal_first_order() used_names = frozenset(x.name for x in il.sig.symbols.values()) def witness(v): c = lg.Const('@' + v.name, v.sort) assert c.name not in used_names return c clauses = dual_clauses(conj, witness) ag = self.new_ag() with ag.context as ac: # post = ac.new_state(ag.init_cond) ag.add_initial_state(ag.init_cond) post = ag.states[0] if 'initialize' in im.module.actions: print "got here" init_action = im.module.actions['initialize'] post = ag.execute(init_action, None, None, 'initialize') for n in range(n_steps + 1): res = ivy_trace.check_final_cond(ag, post, clauses, [], True) # res = ag.bmc(post, clauses) if verbose: if res is None: msg = 'BMC with bound {} did not find a counter-example to:\n{}'.format( n, str(conj.to_formula()), ) else: msg = 'BMC with bound {} found a counter-example to:\n{}'.format( n, str(conj.to_formula()), ) print '\n' + msg + '\n' if res is not None: # ta.step() cmd = lambda: self.ui_parent.add( res, ui_class=ivy_ui.AnalysisGraphUI) self.ui_parent.text_dialog( 'BMC with bound {} found a counter-example to:'.format( n), str(conj.to_formula()), command=cmd, command_label='View') return True post = ag.execute(step_action) if tell_unsat: self.ui_parent.text_dialog( 'BMC with bound {} did not find a counter-example to:'. format(n_steps), str(conj.to_formula()), on_cancel=None) return False
def add_post_axioms(update, axioms): map = dict((sym, new(sym)) for sym in update[0]) syms = set(update[0]) post_ax = clauses_using_symbols(syms, axioms) return (update[0], and_clauses(update[1], rename_clauses(post_ax, map)), update[2])
def constrain_state(upd,fmla): return (upd[0],and_clauses(upd[1],formula_to_clauses(fmla)),upd[2])
def check_inductiveness(self, button=None): import ivy_transrel from ivy_solver import get_small_model from proof import ProofGoal from ivy_logic_utils import Clauses, and_clauses, dual_clauses from random import randrange with self.ui_parent.run_context(): ag = self.new_ag() pre = State() pre.clauses = and_clauses(*self.conjectures) action = im.module.actions['ext'] with EvalContext(check=False): # don't check safety post = ag.execute(action, pre, None, 'ext') post.clauses = ilu.true_clauses() to_test = list(self.conjectures) + [None] # None = check safety while len(to_test) > 0: # choose randomly, so the user can get another result by # clicking again conj = to_test.pop(randrange(len(to_test))) assert conj == None or conj.is_universal_first_order() used_names = frozenset(x.name for x in il.sig.symbols.values()) def witness(v): c = lg.Const('@' + v.name, v.sort) assert c.name not in used_names return c # TODO: this is still a bit hacky, and without nice error reporting if self.relations_to_minimize.value == 'relations to minimize': self.relations_to_minimize.value = ' '.join( sorted(k for k, v in il.sig.symbols.iteritems() if ( type(v.sort) is lg.FunctionSort and v.sort.range == lg.Boolean and v.name not in self.transitive_relations and '.' not in v.name))) if conj == None: # check safety clauses = ilu.true_clauses() rels_to_min = [ il.sig.symbols[x] for x in self.relations_to_minimize.value.split() ] else: clauses = dual_clauses(conj, witness) history = ag.get_history(post) rels_to_min = [ # TODO: this is still a bit hacky, and without nice error reporting history.maps[0].get(relation, relation) for x in self.relations_to_minimize.value.split() for relation in [il.sig.symbols[x]] ], _get_model_clauses = lambda clauses, final_cond=False: get_small_model( clauses, sorted(il.sig.sorts.values()), rels_to_min, final_cond=final_cond) if conj == None: print "check safety" res = ag.check_bounded_safety(post, _get_model_clauses) else: res = ag.bmc(post, clauses, None, None, _get_model_clauses) if res is not None: self.current_conjecture = conj assert len(res.states) == 2 # self.set_states(res.states[0], res.states[1]) # self.cti = self.ui_parent.add(res) self.g = res self.rebuild() self.view_state(self.g.states[0], reset=True) self.show_used_relations(clauses) #self.post_graph.selected = self.get_relevant_elements(self.post_state[2], clauses) if conj == None: self.ui_parent.ok_dialog( 'An assertion failed. A failing state is displayed. You can decompose\nthe failing action observe the failing execution. ' ) else: self.ui_parent.text_dialog( 'The following conjecture is not relatively inductive:', str(conj.to_formula()), on_cancel=None) self.have_cti = True return False # self.set_states(False, False) self.ui_parent.text_dialog( 'Inductive invariant found:', '\n'.join(str(conj) for conj in self.conjectures)) self.have_cti = False return True
def summarize_isolate(mod): global check_lineno check_lineno = act.checked_assert.get() if check_lineno == "": check_lineno = None # print 'check_lineno: {}'.format(check_lineno) check = not opt_summary.get() subgoalmap = dict((x.id,y) for x,y in im.module.subgoals) axioms = [m for m in mod.labeled_axioms if m.id not in subgoalmap] schema_instances = [m for m in mod.labeled_axioms if m.id in subgoalmap] if axioms: print "\n The following properties are assumed as axioms:" for lf in axioms: print pretty_lf(lf) if mod.definitions: print "\n The following definitions are used:" for lf in mod.definitions: print pretty_lf(lf) if mod.labeled_props or schema_instances: print "\n The following properties are to be checked:" if check: for lf in schema_instances: print pretty_lf(lf) + " [proved by axiom schema]" ag = ivy_art.AnalysisGraph() pre = itp.State() props = [x for x in im.module.labeled_props if not x.temporal] fcs = ([(ConjAssumer if prop.id in subgoalmap else ConjChecker)(prop) for prop in props]) check_fcs_in_state(mod,ag,pre,fcs) else: for lf in schema_instances + mod.labeled_props: print pretty_lf(lf) # after checking properties, make them axioms im.module.labeled_axioms.extend(im.module.labeled_props) im.module.update_theory() if mod.labeled_inits: print "\n The following properties are assumed initially:" for lf in mod.labeled_inits: print pretty_lf(lf) if mod.labeled_conjs: print "\n The inductive invariant consists of the following conjectures:" for lf in mod.labeled_conjs: print pretty_lf(lf) if mod.isolate_info.implementations: print "\n The following action implementations are present:" for mixer,mixee,action in sorted(mod.isolate_info.implementations,key=lambda x: x[0]): print " {}implementation of {}".format(pretty_lineno(action),mixee) if mod.isolate_info.monitors: print "\n The following action monitors are present:" for mixer,mixee,action in sorted(mod.isolate_info.monitors,key=lambda x: x[0]): print " {}monitor of {}".format(pretty_lineno(action),mixee) # if mod.actions: # print "\n The following actions are present:" # for actname,action in sorted(mod.actions.iteritems()): # print " {}{}".format(pretty_lineno(action),actname) if mod.initializers: print "\n The following initializers are present:" for actname,action in sorted(mod.initializers, key=lambda x: x[0]): print " {}{}".format(pretty_lineno(action),actname) if mod.labeled_conjs: print "\n Initialization must establish the invariant" if check: with itp.EvalContext(check=False): ag = ivy_art.AnalysisGraph(initializer=lambda x:None) check_conjs_in_state(mod,ag,ag.states[0]) else: print '' if mod.initializers: print "\n Any assertions in initializers must be checked", if check: ag = ivy_art.AnalysisGraph(initializer=lambda x:None) fail = itp.State(expr = itp.fail_expr(ag.states[0].expr)) check_safety_in_state(mod,ag,fail) checked_actions = get_checked_actions() if checked_actions and mod.labeled_conjs: print "\n The following set of external actions must preserve the invariant:" for actname in sorted(checked_actions): action = mod.actions[actname] print " {}{}".format(pretty_lineno(action),actname) if check: ag = ivy_art.AnalysisGraph() pre = itp.State() pre.clauses = lut.and_clauses(*mod.conjs) with itp.EvalContext(check=False): # don't check safety post = ag.execute(action, pre, None, actname) check_conjs_in_state(mod,ag,post,indent=12) else: print '' callgraph = defaultdict(list) for actname,action in mod.actions.iteritems(): for called_name in action.iter_calls(): callgraph[called_name].append(actname) some_assumps = False for actname,action in mod.actions.iteritems(): assumptions = [sub for sub in action.iter_subactions() if isinstance(sub,act.AssumeAction)] if assumptions: if not some_assumps: print "\n The following program assertions are treated as assumptions:" some_assumps = True callers = callgraph[actname] if actname in mod.public_actions: callers.append("the environment") prettyname = actname[4:] if actname.startswith('ext:') else actname prettycallers = [c[4:] if c.startswith('ext:') else c for c in callers] print " in action {} when called from {}:".format(prettyname,','.join(prettycallers)) for sub in assumptions: print " {}assumption".format(pretty_lineno(sub)) tried = set() some_guarants = False for actname,action in mod.actions.iteritems(): guarantees = [sub for sub in action.iter_subactions() if isinstance(sub,(act.AssertAction,act.Ranking))] if check_lineno is not None: guarantees = [sub for sub in guarantees if sub.lineno == check_lineno] if guarantees: if not some_guarants: print "\n The following program assertions are treated as guarantees:" some_guarants = True callers = callgraph[actname] if actname in mod.public_actions: callers.append("the environment") prettyname = actname[4:] if actname.startswith('ext:') else actname prettycallers = [c[4:] if c.startswith('ext:') else c for c in callers] print " in action {} when called from {}:".format(prettyname,','.join(prettycallers)) roots = set(iu.reachable([actname],lambda x: callgraph[x])) for sub in guarantees: print " {}guarantee".format(pretty_lineno(sub)), if check and sub.lineno not in tried: print_dots() tried.add(sub.lineno) old_checked_assert = act.checked_assert.get() act.checked_assert.value = sub.lineno some_failed = False for root in checked_actions: if root in roots: ag = ivy_art.AnalysisGraph() pre = itp.State() pre.clauses = lut.and_clauses(*mod.conjs) with itp.EvalContext(check=False): post = ag.execute_action(root,prestate=pre) fail = itp.State(expr = itp.fail_expr(post.expr)) if not check_safety_in_state(mod,ag,fail,report_pass=False): some_failed = True break if not some_failed: print 'PASS' act.checked_assert.value = old_checked_assert else: print ""
def try_conjectures(s): axioms = _analysis_session.analysis_state.ivy_interp.background_theory() premise = (and_clauses(axioms, s.clauses)).to_formula() return [('conj: {}'.format(conj), try_conjecture, conj) for conj in _analysis_session.analysis_state.ivy_interp.conjs if not z3_implies(premise, conj.to_formula())]
def clauses_model_to_diagram(clauses1, ignore=None, implied=None, model=None, axioms=None, weaken=True): """ Return a diagram of a model of clauses1 or None. The function "ignore", if provided, returns true for symbols that should be ignored in the diagram. """ print "clauses_model_to_diagram clauses1 = {}".format(clauses1) if axioms == None: axioms = true_clauses h = model_if_none(and_clauses(clauses1, axioms), implied, model) ignore = ignore if ignore != None else lambda x: False res = model_facts(h, (lambda x: False), clauses1, upclose=True) # why not pass axioms? print "clauses_model_to_diagram res = {}".format(res) # find representative elements # find representatives of universe elements reps = dict() for c in used_constants_clauses(clauses1): # print "constant: {}".format(c) mc = get_model_constant(h.model, ivy_logic.Constant(c)) # print "value: {}".format(mc) if mc.rep not in reps or reps[ mc.rep].rep.is_skolem() and not c.is_skolem(): reps[mc.rep] = ivy_logic.Constant(c) for s in h.sorts(): for e in h.sort_universe(s): if e.rep not in reps: reps[e.rep] = e.rep.skolem()() print "clauses_model_to_diagram reps = {}".format(reps) # filter out clauses using universe elements without reps # res = [cls for cls in res if all(c in reps for c in used_constants_clause(cls))] # replace universe elements with their reps print "clauses_model_to_diagram res = {}".format(res) res = substitute_constants_clauses(res, reps) # filter defined skolems # this caused a bug in the leader example. the generated diagram did not satisfy clauses1 res.fmlas = [ f for f in res.fmlas if not any((x.is_skolem() and x in clauses1.defidx) for x in used_symbols_ast(f)) ] print "clauses_model_to_diagram res = {}".format(res) uc = Clauses([[ ivy_logic._eq_lit(ivy_logic.Variable('X', c.get_sort()), reps[c.rep]) for c in h.sort_universe(s) ] for s in h.sorts()]) print "clauses_model_to_diagram uc = {}".format(uc) # uc = true_clauses() if weaken: res = unsat_core(res, and_clauses(uc, axioms), clauses1) # implied not used here print "clauses_model_to_diagram res = {}".format(res) # print "foo = {}".format(unsat_core(and_clauses(uc,axioms),true_clauses(),clauses1)) # filter out non-rep skolems repset = set(c.rep for e, c in reps.iteritems()) print "clauses_model_to_diagram repset = {}".format(repset) ign = lambda x, ignore=ignore: (ignore(x) and not x in repset) res = Clauses([ cl for cl in res.fmlas if not any(ign(c) for c in used_symbols_ast(cl)) ]) print "clauses_model_to_diagram res = {}".format(res) return res