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 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 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 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 subst_action(update,subst): assert isinstance(update,SemActionValue) syms = dict(subst.iteritems()) syms.update((new(s),new(syms[s])) for s in update.modset if s in syms) new_updated = [subst.get(s,s) for s in update.modset] new_tr = rename_clauses(update.trans,syms) new_pre = rename_clauses(update.fail,syms) return type(update)(new_updated,new_tr,new_pre)
def subst_action(update, subst): assert isinstance(update, SemActionValue) syms = dict(subst.iteritems()) syms.update((new(s), new(syms[s])) for s in update.modset if s in syms) new_updated = [subst.get(s, s) for s in update.modset] new_tr = rename_clauses(update.trans, syms) new_pre = rename_clauses(update.fail, syms) return type(update)(new_updated, new_tr, new_pre)
def subst_action(update,subst): print subst syms = dict(subst.iteritems()) syms.update((new(s),new(syms[s])) for s in update[0] if s in syms) print syms new_updated = [subst.get(s,s) for s in update[0]] new_tr = rename_clauses(update[1],syms) new_pre = rename_clauses(update[2],syms) return (new_updated,new_tr,new_pre)
def subst_action(update, subst): print subst syms = dict(subst.iteritems()) syms.update((new(s), new(syms[s])) for s in update[0] if s in syms) print syms new_updated = [subst.get(s, s) for s in update[0]] new_tr = rename_clauses(update[1], syms) new_pre = rename_clauses(update[2], syms) return (new_updated, new_tr, new_pre)
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 decompose(self, pre, post, fail=False): v = self.get_callee() if not isinstance(v, Action): return [] actual_params = self.args[0].args actual_returns = self.args[1:] vocab = list(symbols_asts(actual_params + actual_returns)) formals = v.formal_params + v.formal_returns premap, pre = hide_state_map(formals, pre) postmap, post = hide_state_map(formals, post) actual_params = [rename_ast(p, premap) for p in actual_params] actual_returns = [rename_ast(p, postmap) for p in actual_returns] pre = constrain_state( pre, And(* [Equals(x, y) for x, y in zip(actual_params, v.formal_params)])) if not fail: post = constrain_state( post, And(*[ Equals(x, y) for x, y in zip(actual_returns, v.formal_returns) ])) ren = dict((x, x.prefix('__hide:')) for x in actual_returns) post = (post[0], rename_clauses(post[1], ren), post[2]) callee = v.clone(v.args) # drop the formals res = [(pre, [callee], post)] print "decompose call:" print "pre = {}".format(pre) print "callee = {}".format(callee) print "post = {}".format(post) return res
def exist_quant_map(syms,clauses): used = used_symbols_clauses(clauses) rn = UniqueRenamer('__',used) map1 = dict() for s in syms: map1[s] = rename(s,rn) return map1,rename_clauses(clauses,map1)
def exist_quant_map(syms, clauses): used = used_symbols_clauses(clauses) rn = UniqueRenamer('__', used) map1 = dict() for s in syms: map1[s] = rename(s, rn) return map1, rename_clauses(clauses, map1)
def extract_pre_post_model(clauses,model,updated): renaming = dict((v,new(v)) for v in updated) ignore = lambda s: s.is_skolem() or is_new(s) pre_clauses = clauses_model_to_clauses(clauses,ignore = ignore,model = model,numerals=use_numerals()) ignore = lambda s: s.is_skolem() or (not is_new(s) and s in renaming) post_clauses = clauses_model_to_clauses(clauses,ignore = ignore,model = model,numerals=use_numerals()) post_clauses = rename_clauses(post_clauses,inverse_map(renaming)) return map(remove_taut_eqs_clauses,(pre_clauses,post_clauses))
def reverse_image(post_state,axioms,update): updated, clauses, _precond = update post_ax = clauses_using_symbols(updated,axioms) post_clauses = conjoin(post_state,post_ax) post_clauses = rename_clauses(post_clauses, dict((x,new(x)) for x in updated)) post_updated = [new(s) for s in updated] res = exist_quant(post_updated,conjoin(clauses,post_clauses)) # res = simplify_clauses(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 forward_image_map(pre_state,axioms,update): updated, clauses, _precond = update # print "transition_relation: {}".format(clauses) pre_ax = clauses_using_symbols(updated,axioms) pre = conjoin(pre_state,pre_ax) map1,res = exist_quant_map(updated,conjoin(pre,clauses)) res = rename_clauses(res, dict((new(x),x) for x in updated)) ## print "before simp: %s" % res # res = simplify_clauses(res) return map1,res
def action_to_state(update): """ convert from the "action" style to the "state" style """ updated,tr,pre = update renaming = dict() for s in updated: renaming[s] = old(s) for s in used_symbols_clauses(tr): if is_new(s): renaming[s] = new_of(s) return (updated,rename_clauses(tr,renaming),pre)
def action_to_state(update): """ convert from the "action" style to the "state" style """ updated, tr, pre = update renaming = dict() for s in updated: renaming[s] = old(s) for s in used_symbols_clauses(tr): if is_new(s): renaming[s] = new_of(s) return (updated, rename_clauses(tr, renaming), pre)
def forward_image_map(pre_state, axioms, update): updated, clauses, _precond = update # print "transition_relation: {}".format(clauses) pre_ax = clauses_using_symbols(updated, axioms) pre = conjoin(pre_state, pre_ax) map1, res = exist_quant_map(updated, conjoin(pre, clauses)) res = rename_clauses(res, dict((new(x), x) for x in updated)) ## print "before simp: %s" % res # res = simplify_clauses(res) return map1, res
def action_to_state(update): """ convert from the "action" style to the "state" style """ assert isinstance(state,SemActionValue) updated,tr,pre = update.comps renaming = dict() for s in updated: renaming[s] = old(s) for s in used_symbols_clauses(tr): if is_new(s): renaming[s] = new_of(s) return SemStateValue(updated,rename_clauses(tr,renaming),pre)
def reverse_image(post_state,update): assert isinstance(post_state,Clauses) and isinstance(update,SemActionValue) updated, clauses, _precond = update.comps axioms = im.background_theory() post_ax = clauses_using_symbols(updated,axioms) post_clauses = conjoin(post_state,post_ax) post_clauses = rename_clauses(post_clauses, dict((x,new(x)) for x in updated)) post_updated = [new(s) for s in updated] res = exist_quant(post_updated,conjoin(clauses,post_clauses)) # res = simplify_clauses(res) return res
def state_to_action(update): """ convert from the "state" style to the "action" style """ updated,postcond,pre = update postcond,pre = clausify(postcond), clausify(pre) renaming = dict() for s in updated: renaming[s] = new(s) for s in used_symbols_clauses(postcond): if is_old(s): renaming[s] = old_of(s) return (updated,rename_clauses(postcond,renaming),pre)
def action_to_state(update): """ convert from the "action" style to the "state" style """ assert isinstance(state, SemActionValue) updated, tr, pre = update.comps renaming = dict() for s in updated: renaming[s] = old(s) for s in used_symbols_clauses(tr): if is_new(s): renaming[s] = new_of(s) return SemStateValue(updated, rename_clauses(tr, renaming), pre)
def state_to_action(update): """ convert from the "state" style to the "action" style """ updated, postcond, pre = update postcond, pre = clausify(postcond), clausify(pre) renaming = dict() for s in updated: renaming[s] = new(s) for s in used_symbols_clauses(postcond): if is_old(s): renaming[s] = old_of(s) return (updated, rename_clauses(postcond, renaming), 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 state_to_action(update): """ convert from the "state" style to the "action" style """ assert isinstance(update,SemStateValue) updated,postcond,pre = update.comps postcond,pre = clausify(postcond), clausify(pre) renaming = dict() for s in updated: renaming[s] = new(s) for s in used_symbols_clauses(postcond): if is_old(s): renaming[s] = old_of(s) return SemActionValue(updated,rename_clauses(postcond,renaming),pre)
def forward_image_map(pre_state,update): assert isinstance(pre_state,Clauses) and isinstance(update,SemActionValue) updated, clauses, _precond = update.comps # print "transition_relation: {}".format(clauses) axioms = im.background_theory() pre_ax = clauses_using_symbols(updated,axioms) pre = conjoin(pre_state,pre_ax) map1,res = exist_quant_map(updated,conjoin(pre,clauses)) res = rename_clauses(res, dict((new(x),x) for x in updated)) ## print "before simp: %s" % res # res = simplify_clauses(res) return map1,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 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 state_to_action(update): """ convert from the "state" style to the "action" style """ assert isinstance(update, SemStateValue) updated, postcond, pre = update.comps postcond, pre = clausify(postcond), clausify(pre) renaming = dict() for s in updated: renaming[s] = new(s) for s in used_symbols_clauses(postcond): if is_old(s): renaming[s] = old_of(s) return SemActionValue(updated, rename_clauses(postcond, renaming), pre)
def reverse_image(post_state, update): assert isinstance(post_state, Clauses) and isinstance( update, SemActionValue) updated, clauses, _precond = update.comps axioms = im.background_theory() post_ax = clauses_using_symbols(updated, axioms) post_clauses = conjoin(post_state, post_ax) post_clauses = rename_clauses(post_clauses, dict((x, new(x)) for x in updated)) post_updated = [new(s) for s in updated] res = exist_quant(post_updated, conjoin(clauses, post_clauses)) # res = simplify_clauses(res) return res
def forward_image_map(pre_state, update): assert isinstance(pre_state, Clauses) and isinstance( update, SemActionValue) updated, clauses, _precond = update.comps # print "transition_relation: {}".format(clauses) axioms = im.background_theory() pre_ax = clauses_using_symbols(updated, axioms) pre = conjoin(pre_state, pre_ax) map1, res = exist_quant_map(updated, conjoin(pre, clauses)) res = rename_clauses(res, dict((new(x), x) for x in updated)) ## print "before simp: %s" % res # res = simplify_clauses(res) return map1, res
def rename_distinct(clauses1, clauses2): """ rename skolems in clauses1 so they don't occur in clauses2. """ # print "rename_distinct clauses1 = {}".format(clauses1) # print "rename_distinct clauses2 = {!r}".format(clauses2) used1 = used_symbols_clauses(clauses1) used2 = used_symbols_clauses(clauses2) rn = UniqueRenamer('', used2) map1 = dict() for s in used1: if is_skolem(s) and not is_global_skolem(s): map1[s] = rename(s, rn) return rename_clauses(clauses1, map1)
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 rename_distinct(clauses1,clauses2): """ rename skolems in clauses1 so they don't occur in clauses2. """ # print "rename_distinct clauses1 = {}".format(clauses1) # print "rename_distinct clauses2 = {!r}".format(clauses2) used1 = used_symbols_clauses(clauses1) used2 = used_symbols_clauses(clauses2) rn = UniqueRenamer('',used2) map1 = dict() for s in used1: if is_skolem(s): map1[s] = rename(s,rn) return rename_clauses(clauses1,map1)
def decompose(self, pre, post): v = self.get_callee() if not isinstance(v, Action): return [] actual_params = self.args[0].args actual_returns = self.args[1:] vocab = list(symbols_asts(actual_params + actual_returns)) formals = v.formal_params + v.formal_returns premap, pre = hide_state_map(formals, pre) postmap, post = hide_state_map(formals, post) actual_params = [rename_ast(p, premap) for p in actual_params] actual_returns = [rename_ast(p, postmap) for p in actual_returns] pre = constrain_state(pre, And(*[Equals(x, y) for x, y in zip(actual_params, v.formal_params)])) post = constrain_state(post, And(*[Equals(x, y) for x, y in zip(actual_returns, v.formal_returns)])) ren = dict((x, x.prefix("__hide:")) for x in actual_returns) post = (post[0], rename_clauses(post[1], ren), post[2]) callee = v.clone(v.args) # drop the formals return [(pre, [callee], post)]
def bind_olds_clauses(clauses): subst = dict((s,old_of(s)) for s in used_symbols_clauses(clauses) if is_old(s)) return rename_clauses(clauses,subst)
def forward_clauses(clauses,inflex): return lu.rename_clauses(clauses, dict((x,tr.new(x)) for x in lu.used_symbols_clauses(clauses) if x != '=' and x not in inflex))
def bind_olds_clauses(clauses): subst = dict( (s, old_of(s)) for s in used_symbols_clauses(clauses) if is_old(s)) return rename_clauses(clauses, subst)
def forward_clauses(clauses, inflex): return lu.rename_clauses( clauses, dict((x, tr.new(x)) for x in lu.used_symbols_clauses(clauses) if x != '=' and x not in inflex))
def to_aiger(mod,ext_act): erf = il.Symbol('err_flag',il.find_sort('bool')) errconds = [] add_err_flag_mod(mod,erf,errconds) # we use a special state variable __init to indicate the initial state ext_acts = [mod.actions[x] for x in sorted(mod.public_actions)] ext_act = ia.EnvAction(*ext_acts) init_var = il.Symbol('__init',il.find_sort('bool')) init = add_err_flag(ia.Sequence(*([a for n,a in mod.initializers]+[ia.AssignAction(init_var,il.And())])),erf,errconds) action = ia.Sequence(ia.AssignAction(erf,il.Or()),ia.IfAction(init_var,ext_act,init)) # get the invariant to be proved, replacing free variables with # skolems. First, we apply any proof tactics. pc = ivy_proof.ProofChecker(mod.axioms,mod.definitions,mod.schemata) pmap = dict((lf.id,p) for lf,p in mod.proofs) conjs = [] for lf in mod.labeled_conjs: if lf.id in pmap: proof = pmap[lf.id] subgoals = pc.admit_proposition(lf,proof) conjs.extend(subgoals) else: conjs.append(lf) invariant = il.And(*[il.drop_universals(lf.formula) for lf in conjs]) # iu.dbg('invariant') skolemizer = lambda v: ilu.var_to_skolem('__',il.Variable(v.rep,v.sort)) vs = ilu.used_variables_in_order_ast(invariant) sksubs = dict((v.rep,skolemizer(v)) for v in vs) invariant = ilu.substitute_ast(invariant,sksubs) invar_syms = ilu.used_symbols_ast(invariant) # compute the transition relation stvars,trans,error = action.update(mod,None) # print 'action : {}'.format(action) # print 'annotation: {}'.format(trans.annot) annot = trans.annot # match_annotation(action,annot,MatchHandler()) indhyps = [il.close_formula(il.Implies(init_var,lf.formula)) for lf in mod.labeled_conjs] # trans = ilu.and_clauses(trans,indhyps) # save the original symbols for trace orig_syms = ilu.used_symbols_clauses(trans) orig_syms.update(ilu.used_symbols_ast(invariant)) # TODO: get the axioms (or maybe only the ground ones?) # axioms = mod.background_theory() # rn = dict((sym,tr.new(sym)) for sym in stvars) # next_axioms = ilu.rename_clauses(axioms,rn) # return ilu.and_clauses(axioms,next_axioms) funs = set() for df in trans.defs: funs.update(ilu.used_symbols_ast(df.args[1])) for fmla in trans.fmlas: funs.update(ilu.used_symbols_ast(fmla)) # funs = ilu.used_symbols_clauses(trans) funs.update(ilu.used_symbols_ast(invariant)) funs = set(sym for sym in funs if il.is_function_sort(sym.sort)) iu.dbg('[str(fun) for fun in funs]') # Propositionally abstract # step 1: get rid of definitions of non-finite symbols by turning # them into constraints new_defs = [] new_fmlas = [] for df in trans.defs: if len(df.args[0].args) == 0 and is_finite_sort(df.args[0].sort): new_defs.append(df) else: fmla = df.to_constraint() new_fmlas.append(fmla) trans = ilu.Clauses(new_fmlas+trans.fmlas,new_defs) # step 2: get rid of ite's over non-finite sorts, by introducing constraints cnsts = [] new_defs = [elim_ite(df,cnsts) for df in trans.defs] new_fmlas = [elim_ite(fmla,cnsts) for fmla in trans.fmlas] trans = ilu.Clauses(new_fmlas+cnsts,new_defs) # step 3: eliminate quantfiers using finite instantiations from_asserts = il.And(*[il.Equals(x,x) for x in ilu.used_symbols_ast(il.And(*errconds)) if tr.is_skolem(x) and not il.is_function_sort(x.sort)]) iu.dbg('from_asserts') invar_syms.update(ilu.used_symbols_ast(from_asserts)) sort_constants = mine_constants(mod,trans,il.And(invariant,from_asserts)) sort_constants2 = mine_constants2(mod,trans,invariant) print '\ninstantiations:' trans,invariant = Qelim(sort_constants,sort_constants2)(trans,invariant,indhyps) # print 'after qe:' # print 'trans: {}'.format(trans) # print 'invariant: {}'.format(invariant) # step 4: instantiate the axioms using patterns # We have to condition both the transition relation and the # invariant on the axioms, so we define a boolean symbol '__axioms' # to represent the axioms. axs = instantiate_axioms(mod,stvars,trans,invariant,sort_constants,funs) ax_conj = il.And(*axs) ax_var = il.Symbol('__axioms',ax_conj.sort) ax_def = il.Definition(ax_var,ax_conj) invariant = il.Implies(ax_var,invariant) trans = ilu.Clauses(trans.fmlas+[ax_var],trans.defs+[ax_def]) # step 5: eliminate all non-propositional atoms by replacing with fresh booleans # An atom with next-state symbols is converted to a next-state symbol if possible stvarset = set(stvars) prop_abs = dict() # map from atoms to proposition variables global prop_abs_ctr # sigh -- python lameness prop_abs_ctr = 0 # counter for fresh symbols new_stvars = [] # list of fresh symbols # get the propositional abstraction of an atom def new_prop(expr): res = prop_abs.get(expr,None) if res is None: prev = prev_expr(stvarset,expr,sort_constants) if prev is not None: # print 'stvar: old: {} new: {}'.format(prev,expr) pva = new_prop(prev) res = tr.new(pva) new_stvars.append(pva) prop_abs[expr] = res # prevent adding this again to new_stvars else: global prop_abs_ctr res = il.Symbol('__abs[{}]'.format(prop_abs_ctr),expr.sort) # print '{} = {}'.format(res,expr) prop_abs[expr] = res prop_abs_ctr += 1 return res # propositionally abstract an expression global mk_prop_fmlas mk_prop_fmlas = [] def mk_prop_abs(expr): if il.is_quantifier(expr) or len(expr.args) > 0 and any(not is_finite_sort(a.sort) for a in expr.args): return new_prop(expr) return expr.clone(map(mk_prop_abs,expr.args)) # apply propositional abstraction to the transition relation new_defs = map(mk_prop_abs,trans.defs) new_fmlas = [mk_prop_abs(il.close_formula(fmla)) for fmla in trans.fmlas] # find any immutable abstract variables, and give them a next definition def my_is_skolem(x): res = tr.is_skolem(x) and x not in invar_syms return res def is_immutable_expr(expr): res = not any(my_is_skolem(sym) or tr.is_new(sym) or sym in stvarset for sym in ilu.used_symbols_ast(expr)) return res for expr,v in prop_abs.iteritems(): if is_immutable_expr(expr): new_stvars.append(v) print 'new state: {}'.format(expr) new_defs.append(il.Definition(tr.new(v),v)) trans = ilu.Clauses(new_fmlas+mk_prop_fmlas,new_defs) # apply propositional abstraction to the invariant invariant = mk_prop_abs(invariant) # create next-state symbols for atoms in the invariant (is this needed?) rn = dict((sym,tr.new(sym)) for sym in stvars) mk_prop_abs(ilu.rename_ast(invariant,rn)) # this is to pick up state variables from invariant # update the state variables by removing the non-finite ones and adding the fresh state booleans stvars = [sym for sym in stvars if is_finite_sort(sym.sort)] + new_stvars # iu.dbg('trans') # iu.dbg('stvars') # iu.dbg('invariant') # exit(0) # For each state var, create a variable that corresponds to the input of its latch # Also, havoc all the state bits except the init flag at the initial time. This # is needed because in aiger, all latches start at 0! def fix(v): return v.prefix('nondet') def curval(v): return v.prefix('curval') def initchoice(v): return v.prefix('initchoice') stvars_fix_map = dict((tr.new(v),fix(v)) for v in stvars) stvars_fix_map.update((v,curval(v)) for v in stvars if v != init_var) trans = ilu.rename_clauses(trans,stvars_fix_map) # iu.dbg('trans') new_defs = trans.defs + [il.Definition(ilu.sym_inst(tr.new(v)),ilu.sym_inst(fix(v))) for v in stvars] new_defs.extend(il.Definition(curval(v),il.Ite(init_var,v,initchoice(v))) for v in stvars if v != init_var) trans = ilu.Clauses(trans.fmlas,new_defs) # Turn the transition constraint into a definition cnst_var = il.Symbol('__cnst',il.find_sort('bool')) new_defs = list(trans.defs) new_defs.append(il.Definition(tr.new(cnst_var),fix(cnst_var))) new_defs.append(il.Definition(fix(cnst_var),il.Or(cnst_var,il.Not(il.And(*trans.fmlas))))) stvars.append(cnst_var) trans = ilu.Clauses([],new_defs) # Input are all the non-defined symbols. Output indicates invariant is false. # iu.dbg('trans') def_set = set(df.defines() for df in trans.defs) def_set.update(stvars) # iu.dbg('def_set') used = ilu.used_symbols_clauses(trans) used.update(ilu.symbols_ast(invariant)) inputs = [sym for sym in used if sym not in def_set and not il.is_interpreted_symbol(sym)] fail = il.Symbol('__fail',il.find_sort('bool')) outputs = [fail] # iu.dbg('trans') # make an aiger aiger = Encoder(inputs,stvars,outputs) comb_defs = [df for df in trans.defs if not tr.is_new(df.defines())] invar_fail = il.Symbol('invar__fail',il.find_sort('bool')) # make a name for invariant fail cond comb_defs.append(il.Definition(invar_fail,il.Not(invariant))) aiger.deflist(comb_defs) for df in trans.defs: if tr.is_new(df.defines()): aiger.set(tr.new_of(df.defines()),aiger.eval(df.args[1])) miter = il.And(init_var,il.Not(cnst_var),il.Or(invar_fail,il.And(fix(erf),il.Not(fix(cnst_var))))) aiger.set(fail,aiger.eval(miter)) # aiger.sub.debug() # make a decoder for the abstract propositions decoder = dict((y,x) for x,y in prop_abs.iteritems()) for sym in aiger.inputs + aiger.latches: if sym not in decoder and sym in orig_syms: decoder[sym] = sym cnsts = set(sym for syms in sort_constants.values() for sym in syms) return aiger,decoder,annot,cnsts,action,stvarset
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])