def show_used_relations(self, clauses, both=False): self.current_concept_graph.clear_edges() rels = self.current_concept_graph.g.relations used = set( il.normalize_symbol(s) for s in lu.used_constants(clauses.to_formula())) for rel in rels: fmla = rel.formula if any(c in used and not c.name.startswith('@') for c in lu.used_constants(fmla)): self.current_concept_graph.show_relation(rel, '+', update=False) if both and not il.is_enumerated(fmla): self.current_concept_graph.show_relation(rel, '-', update=False) need_update_relations = False for app in ilu.apps_clauses(clauses): if len(app.args) == 3 and il.is_numeral(app.args[0]): fmla = app.rep(app.args[0], il.Variable('X', app.args[1].sort), il.Variable('Y', app.args[2].sort)) concept = self.current_concept_graph.g.formula_to_concept(fmla) self.current_concept_graph.g.new_relation(concept) need_update_relations = True self.current_concept_graph.show_relation(concept, '+', update=False) if both: self.current_concept_graph.show_relation(concept, '-', update=False) if need_update_relations: self.current_concept_graph.update_relations() self.current_concept_graph.update()
def sort_size_constraint(sort,size): if isinstance(sort,ivy_logic.UninterpretedSort): syms = [ivy_logic.Symbol('__'+sort.name+'$'+str(i),sort) for i in range(size)] v = ivy_logic.Variable('X'+sort.name,sort) res = ivy_logic.Or(*[ivy_logic.Equals(v,s) for s in syms]) # print "sort_size_constraint : {}".format(res) return res return ivy_logic.And()
def compile_native_symbol(arg): name = arg.rep if name in ivy_logic.sig.symbols: sym = ivy_logic.sig.symbols[name] if not isinstance(sym, ivy_logic.UnionSort): return sym if name in ivy_logic.sig.sorts: return ivy_logic.Variable('X', ivy_logic.sig.sorts[name]) if ivy_logic.is_numeral_name(name): return ivy_logic.Symbol(name, ivy_logic.TopS) raise iu.IvyError(arg, '{} is not a declared symbol or type'.format(name))
def model_universe_facts(h,sort,upclose): if ivy_logic.is_interpreted_sort(sort): return [] # get universe elements elems = h.sort_universe(sort) # constraint defining universe uc = [] if not upclose: uc = [[ivy_logic._eq_lit(ivy_logic.Variable('X',c.sort),c) for c in elems]] # universe elements are distinct dc = [[ivy_logic._neq_lit(c1,c2)] for (c1,c2) in iu.distinct_unordered_pairs(elems)] return uc+dc
def sorted_sort_universe(self, sort): elems = self.constants[sort] # print "elems: {}".format(map(str,elems)) vs = [ivy_logic.Variable(s, sort) for s in ["X", "Y"]] order = ivy_logic.Symbol("<", ivy_logic.RelationSort([sort, sort])) order_atom = atom_to_z3(order(*vs)) z3_vs = map(term_to_z3, vs) # print "order_atom: {}".format(order_atom) try: fun = z3.Function self.model[order.to_z3()] # print "sorting..." elems = sorted(elems, SortOrder(z3_vs, order_atom, self.model)) except IndexError: pass # print "elems: {}".format(map(str,elems)) return map(constant_from_z3, elems)
def apply_match(match,fmla): """ apply a match to a formula. In effect, substitute all symbols in the match with the corresponding lambda terms and apply beta reduction """ args = [apply_match(match,f) for f in fmla.args] if il.is_app(fmla): if fmla.rep in match: func = match[fmla.rep] return func(*args) elif il.is_binder(fmla): vs = [apply_match(match,v) for v in fmla.variables] return fmla.clone_binder(vs,apply_match(match,fmla.body)) elif il.is_variable(fmla): return il.Variable(fmla.name,match.get(fmla.sort,fmla.sort)) return fmla.clone(args)
def apply_match_alt(match, fmla): """ apply a match to a formula. In effect, substitute all symbols in the match with the corresponding lambda terms and apply beta reduction """ args = [apply_match_alt(match, f) for f in fmla.args] if il.is_app(fmla): func = apply_match_func(match, fmla.rep) if func in match: func = match[func] return func(*args) return func(*args) if il.is_variable(fmla): fmla = il.Variable(fmla.name, match.get(fmla.sort, fmla.sort)) fmla = match.get(fmla, fmla) return fmla return fmla.clone(args)
def apply_match_alt_rec(match,fmla,env): args = [apply_match_alt_rec(match,f,env) for f in fmla.args] if il.is_app(fmla): if fmla.rep in match: return apply_fun(match_get(match,fmla.rep,env),args) func = apply_match_func(match,fmla.rep) func = match_get(match,func,env,func) return func(*args) if il.is_variable(fmla): if fmla in match: return match_get(match,fmla,env) fmla = il.Variable(fmla.name,apply_match_sort(match,fmla.sort)) fmla = match_get(match,fmla,env,fmla) return fmla if il.is_binder(fmla): with il.BindSymbols(env,fmla.variables): fmla = fmla.clone_binder([apply_match_alt_rec(match,v,env) for v in fmla.variables],args[0]) return fmla return fmla.clone(args)
def parameterize_schema(sorts,schema): """ Add initial parameters to all the free symbols in a schema. Takes a list of sorts and an ia.SchemaBody. """ vars = make_distinct_vars(sorts,goal_conc(schema)) match = {} prems = [] for prem in goal_prems(schema): if isinstance(prem,ia.ConstantDecl): sym = prem.args[0] vs2 = [il.Variable('X'+str(i),y) for i,y in enumerate(sym.sort.dom)] sym2 = sym.resort(il.FuncConstSort(*(sorts + list(sym.sort.dom) + [sym.sort.rng]))) match[sym] = il.Lambda(vs2,sym2(*(vars+vs2))) prems.append(ia.ConstantDecl(sym2)) else: prems.append(prem) conc = apply_match(match,goal_conc(schema)) return clone_goal(schema,prems,conc)
def make_distinct_vars(sorts, *asts): vars = [il.Variable('V' + str(i), sort) for i, sort in enumerate(sorts)] return lu.rename_variables_distinct_asts(vars, asts)
def apply_match_sym(match, sym): if il.is_variable(sym): return il.Variable(sym.name, match.get(sym.sort, sym.sort)) return match.get(sym, sym) if isinstance( sym, il.UninterpretedSort) else apply_match_func(match, sym)
CallAction(*([ivy_ast.Atom(self.rep, args)] + ress))) return ivy_ast.Tuple(*ress) sort = find_sort(returns[0].sort) res = ivy_logic.Symbol('loc:' + str(len(expr_context.local_syms)), sort) expr_context.local_syms.append(res) expr_context.code.append(CallAction(ivy_ast.Atom(self.rep, args), res)) return res() return (ivy_logic.Equals if self.rep == '=' else ivy_logic.find_polymorphic_symbol(self.rep))(*args) ivy_ast.App.cmpl = ivy_ast.Atom.cmpl = compile_app ivy_ast.Variable.cmpl = lambda self: ivy_logic.Variable( self.rep, ivy_logic.find_sort(self.sort) if isinstance(self.sort, str) else self.sort) ivy_ast.ConstantSort.cmpl = lambda self: ivy_logic.ConstantSort(self.rep) ivy_ast.EnumeratedSort.cmpl = lambda self: ivy_logic.EnumeratedSort( self.name, self.extension) SymbolList.cmpl = lambda self: self.clone( [find_symbol(s) for s in self.symbols]) def cquant(q): return ivy_logic.ForAll if isinstance(q, ivy_ast.Forall) else ivy_logic.Exists
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
def loop_action(action, mod): subst = dict((p, ivy_logic.Variable('Y' + p.name, p.sort)) for p in action.formal_params) action = lu.substitute_constants_ast(action, subst) ia.type_check_action(action, mod) # make sure all is legal return action
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