def compile_one_match(lhs,rhs,freesyms,constants): if il.is_variable(lhs): return fo_match(lhs,rhs,freesyms,constants) rhsvs = dict((v.name,v) for v in lu.used_variables_ast(rhs)) vmatches = [{v.sort:rhsvs[v.name].sort} for v in lu.used_variables_ast(lhs) if v.name in rhsvs and v.sort in freesyms] vmatch = merge_matches(*vmatches) if vmatch is None: return None lhs = apply_match_alt(vmatch,lhs) newfreesyms = apply_match_freesyms(vmatch,freesyms) somatch = match(lhs,rhs,newfreesyms,constants) somatch = compose_matches(freesyms,vmatch,somatch,vmatch) fmatch = merge_matches(vmatch,somatch) return fmatch
def bq(fmla): """ Bound the free variables in fmla of uninterpeted sort """ vs = list(sorted(used_variables_ast(fmla))) vs = [v for v in vs if not ivy_logic.is_interpreted_sort(v.sort)] cnsts = [bdv(v) for v in vs] bq_res = ivy_logic.Implies(ivy_logic.And(*cnsts), fmla) if cnsts else fmla return bq_res
def compile_action_def(a,sig): sig = sig.copy() if not hasattr(a.args[1],'lineno'): print a assert hasattr(a.args[1],'lineno') with sig: with ASTContext(a.args[1]): params = a.args[0].args pformals = [v.to_const('prm:') for v in params] if params: subst = dict((x.rep,y) for x,y in zip(params,pformals)) a = ivy_ast.substitute_ast(a,subst) assert hasattr(a.args[1],'lineno') # a = ivy_ast.subst_prefix_atoms_ast(a,subst,None,None) # print "after: %s" % (a) # convert object paramaters to arguments (object-orientation!) formals = [compile_const(v,sig) for v in pformals + a.formal_params] returns = [compile_const(v,sig) for v in a.formal_returns] # print returns res = sortify(a.args[1]) assert hasattr(res,'lineno'), res for suba in res.iter_subactions(): if isinstance(suba,CallAction): if any(lu.used_variables_ast(a) for a in suba.args[0].args): iu.dbg('a.args[0]') iu.dbg('a.formal_params') iu.dbg('suba.lineno') iu.dbg('suba') raise iu.IvyError(suba,"call may not have free variables") res.formal_params = formals res.formal_returns = returns res.label = a.args[0].relname return res
def bq(fmla): """ Bound the free variables in fmla of uninterpeted sort """ vs = list(sorted(used_variables_ast(fmla))) vs = [v for v in vs if not ivy_logic.is_interpreted_sort(v.sort)] cnsts = [bdv(v) for v in vs] bq_res = ivy_logic.Implies(ivy_logic.And(*cnsts),fmla) if cnsts else fmla return bq_res
def fmla_vocab(fmla): """ Get the free vocabulary of a formula, including sorts, symbols and variables """ things = lu.used_sorts_ast(fmla) things.update(lu.used_symbols_ast(fmla)) things.update(lu.used_variables_ast(fmla)) return things
def formula_to_z3(fmla): z3_formula = formula_to_z3_int(fmla) variables = sorted(used_variables_ast(fmla)) if len(variables) == 0: return z3_formula else: z3_variables = [term_to_z3(v) for v in variables] return z3.ForAll(z3_variables, z3_formula)
def update_conjs(self): mod = self for i, cax in enumerate(mod.labeled_conjs): fmla = cax.formula csname = 'conjecture:' + str(i) variables = list(lu.used_variables_ast(fmla)) sort = il.RelationSort([v.sort for v in variables]) sym = il.Symbol(csname, sort) space = ics.NamedSpace(il.Literal(0, fmla)) mod.concept_spaces.append((sym(*variables), space))
def update_conjs(self): mod = self for i,cax in enumerate(mod.labeled_conjs): fmla = cax.formula csname = 'conjecture:'+ str(i) variables = list(lu.used_variables_ast(fmla)) sort = il.RelationSort([v.sort for v in variables]) sym = il.Symbol(csname,sort) space = ics.NamedSpace(il.Literal(0,fmla)) mod.concept_spaces.append((sym(*variables),space))
def get_trigger(expr,vs): if il.is_quantifier(expr) or il.is_variable(expr): return None for a in expr.args: r = get_trigger(a,vs) if r is not None: return r if il.is_app(expr) or il.is_eq(expr): evs = ilu.used_variables_ast(expr) if all(v in evs for v in vs): return expr
def conjecture(self, ax): fmla = sortify_with_inference(ax) try: self.domain.conjs.append(formula_to_clauses(fmla)) except ValueError: raise IvyError(ax, "conjecture must be a clause") # Make a conecpt space from the conjecture csname = 'conjecture:' + str(len(self.domain.conjs)) variables = list(lu.used_variables_ast(fmla)) sort = ivy_logic.RelationSort([v.sort for v in variables]) sym = ivy_logic.Symbol(csname, sort) space = NamedSpace(ivy_logic.Literal(0, fmla)) self.domain.concept_spaces.append((sym(*variables), space))
def conjecture(self,ax): fmla = sortify_with_inference(ax) try: self.domain.conjs.append(formula_to_clauses(fmla)) except ValueError: raise IvyError(ax,"conjecture must be a clause") # Make a conecpt space from the conjecture csname = 'conjecture:'+ str(len(self.domain.conjs)) variables = list(lu.used_variables_ast(fmla)) sort = ivy_logic.RelationSort([v.sort for v in variables]) sym = ivy_logic.Symbol(csname,sort) space = NamedSpace(ivy_logic.Literal(0,fmla)) self.domain.concept_spaces.append((sym(*variables),space))
def create_macro_maps(assumes, asserts, macros): global universally_quantified_variables global macro_var_map global macro_dep_map global macro_map global macro_value_map global strat_map macro_map = dict() for df, lf in macros: macro_map[df.defines()] = (df, lf) macro_dep_map = defaultdict(set) macro_var_map = dict() macro_value_map = dict() def var_map_add(w, vn): if w in macro_var_map: unify(macro_var_map[w], vn) else: macro_var_map[w] = vn for fmla, _ in assumes + asserts + list(reversed(macros)): for app in ilu.apps_ast(fmla): if app.rep in macro_map: mvs = macro_map[app.rep][0].args[0].args for v, w in zip(app.args, mvs): if il.is_variable(w): if il.is_variable(v): if v in universally_quantified_variables: var_map_add(w, strat_map[v]) if v in macro_var_map: var_map_add(w, macro_var_map[v]) if v in macro_dep_map: macro_dep_map[w].update(macro_dep_map[v]) else: for u in ilu.used_variables_ast(v): if u in universally_quantified_variables: macro_dep_map[w].add(strat_map[u]) if u in macro_var_map: macro_dep_map[w].add(macro_var_map[u]) if u in macro_dep_map: macro_dep_map[w].update(macro_var_map[u])
def compile_action_def(a, sig): sig = sig.copy() if not hasattr(a.args[1], 'lineno'): print a assert hasattr(a.args[1], 'lineno') with sig: with ASTContext(a.args[1]): params = a.args[0].args pformals = [v.to_const('prm:') for v in params] if params: subst = dict((x.rep, y) for x, y in zip(params, pformals)) a = ivy_ast.substitute_ast(a, subst) assert hasattr(a.args[1], 'lineno') # a = ivy_ast.subst_prefix_atoms_ast(a,subst,None,None) # print "after: %s" % (a) # convert object paramaters to arguments (object-orientation!) formals = [ compile_const(v, sig) for v in pformals + a.formal_params ] returns = [compile_const(v, sig) for v in a.formal_returns] # print returns res = sortify(a.args[1]) assert hasattr(res, 'lineno'), res for suba in res.iter_subactions(): if isinstance(suba, CallAction): if any( lu.used_variables_ast(a) for a in suba.args[0].args): iu.dbg('a.args[0]') iu.dbg('a.formal_params') iu.dbg('suba.lineno') iu.dbg('suba') raise iu.IvyError(suba, "call may not have free variables") res.formal_params = formals res.formal_returns = returns res.label = a.args[0].relname return res
def instantiate_axioms(mod,stvars,trans,invariant,sort_constants,funs): # Expand the axioms schemata into axioms axioms = mod.labeled_axioms + expand_schemata(mod,sort_constants,funs) for a in axioms: print 'axiom {}'.format(a) # Get all the triggers. For now only automatic triggers def get_trigger(expr,vs): if il.is_quantifier(expr) or il.is_variable(expr): return None for a in expr.args: r = get_trigger(a,vs) if r is not None: return r if il.is_app(expr) or il.is_eq(expr): evs = ilu.used_variables_ast(expr) if all(v in evs for v in vs): return expr triggers = [] for ax in axioms: fmla = ax.formula vs = list(ilu.used_variables_ast(fmla)) if vs: trig = get_trigger(fmla,vs) if trig is not None: # iu.dbg('trig') # iu.dbg('ax') triggers.append((trig,ax)) insts = set() global inst_list # python lamemess -- should be local but inner function cannot access inst_list = [] def match(pat,expr,mp): if il.is_variable(pat): if pat in mp: return expr == mp[pat] mp[pat] = expr return True if il.is_app(pat): return (il.is_app(expr) and pat.rep == expr.rep and all(match(x,y,mp) for x,y in zip(pat.args,expr.args))) if il.is_quantifier(pat): return False if type(pat) is not type(expr): return False if il.is_eq(expr): px,py = pat.args ex,ey = expr.args if px.sort != ex.sort: return False save = mp.copy() if match(px,ex,mp) and match(py,ey,mp): return True mp.clear() mp.update(save) return match(px,ey,mp) and match(py,ex,mp) return all(match(x,y,mp) for x,y in zip(pat.args,expr.args)) # TODO: make sure matches are ground def recur(expr): for e in expr.args: recur(e) for trig,ax in triggers: mp = dict() if match(trig,expr,mp): fmla = normalize(il.substitute(ax.formula,mp)) if fmla not in insts: insts.add(fmla) inst_list.append(fmla) # match triggers against the defs and fmlas and invariant for f in trans.defs + trans.fmlas + [invariant]: recur(f) for f in inst_list: print ' {}'.format(f) return inst_list
def create_isolate(iso, mod=None, **kwargs): mod = mod or im.module # treat initializers as exports after_inits = mod.mixins["init"] del mod.mixins["init"] mod.exports.extend( ivy_ast.ExportDef(ivy_ast.Atom(a.mixer()), ivy_ast.Atom('')) for a in after_inits) # check all mixin declarations for name, mixins in mod.mixins.iteritems(): for mixin in mixins: with ASTContext(mixins): action1, action2 = (lookup_action(mixin, mod, a.relname) for a in mixin.args) # check all the delagate declarations for dl in mod.delegates: lookup_action(dl.args[0], mod, dl.delegated()) if dl.delegee() and dl.delegee() not in mod.hierarchy: raise iu.IvyError(dl.args[1], "{} is not a module instance".format(name)) # check all the export declarations for exp in mod.exports: expname = exp.args[0].rep if expname not in mod.actions: raise iu.IvyError(exp, "undefined action: {}".format(expname)) # create the import actions, if requested extra_with = [] extra_strip = {} if create_imports.get(): newimps = [] for imp in mod.imports: if imp.args[1].rep == '': impname = imp.args[0].rep if impname not in mod.actions: raise iu.IvyError(imp, "undefined action: {}".format(impname)) action = mod.actions[impname] if not (type(action) == ia.Sequence and not action.args): raise iu.IvyError( imp, "cannot import implemented action: {}".format(impname)) extname = 'imp__' + impname call = ia.CallAction( *([ivy_ast.Atom(extname, action.formal_params)] + action.formal_returns)) call.formal_params = action.formal_params call.formal_returns = action.formal_returns call.lineno = action.lineno mod.actions[impname] = call mod.actions[extname] = action newimps.append( ivy_ast.ImportDef(ivy_ast.Atom(extname), imp.args[1])) extra_with.append(ivy_ast.Atom(impname)) # extra_with.append(ivy_ast.Atom(extname)) if iso and iso in mod.isolates: ps = mod.isolates[iso].params() extra_strip[impname] = [a.rep for a in ps] extra_strip[extname] = [a.rep for a in ps] else: newimps.append(imp) mod.imports = newimps mixers = set() for ms in mod.mixins.values(): for m in ms: mixers.add(m.mixer()) # Determine the mixin order (as a side effect on module.mixins) get_mixin_order(iso, mod) # Construct an isolate if iso: isolate_component(mod, iso, extra_with=extra_with, extra_strip=extra_strip) else: if mod.isolates and cone_of_influence.get(): raise iu.IvyError(None, 'no isolate specified on command line') # apply all the mixins in no particular order for name, mixins in mod.mixins.iteritems(): for mixin in mixins: action1, action2 = (lookup_action(mixin, mod, a.relname) for a in mixin.args) mixed = ia.apply_mixin(mixin, action1, action2) mod.actions[mixin.args[1].relname] = mixed # find the globally exported actions (all if none specified, for compat) if mod.exports: mod.public_actions.clear() for e in mod.exports: if not e.scope(): # global export mod.public_actions.add(e.exported()) else: for a in mod.actions: mod.public_actions.add(a) # Create one big external action if requested for name in mod.public_actions: mod.actions[name].label = name ext = kwargs['ext'] if 'ext' in kwargs else ext_action.get() if ext is not None: ext_acts = [mod.actions[x] for x in sorted(mod.public_actions)] ext_act = ia.EnvAction(*ext_acts) mod.public_actions.add(ext) mod.actions[ext] = ext_act # Check native interpretations of symbols slv.check_compat() # Make concept spaces from the conjecture for i, cax in enumerate(mod.labeled_conjs): fmla = cax.formula csname = 'conjecture:' + str(i) variables = list(lu.used_variables_ast(fmla)) sort = ivy_logic.RelationSort([v.sort for v in variables]) sym = ivy_logic.Symbol(csname, sort) space = ics.NamedSpace(ivy_logic.Literal(0, fmla)) mod.concept_spaces.append((sym(*variables), space)) ith.check_theory() # get rid of useless actions cone = get_mod_cone(mod) if cone_of_influence.get(): for a in list(mod.actions): if a not in cone: del mod.actions[a] else: for a in list(mod.actions): if a not in cone and not a.startswith('ext:') and a not in mixers: ea = 'ext:' + a if ea in mod.actions and ea not in cone: if ia.has_code(mod.actions[a]): iu.warn(mod.actions[a], "action {} is never called".format(a)) fix_initializers(mod, after_inits) # show the compiled code if requested if show_compiled.get(): ivy_printer.print_module(mod)
def concept_from_formula(fmla): vs = sorted(list(ilu.used_variables_ast(fmla)), key=str) name = (','.join(str(v) + ':' + str(v.sort) for v in vs) + '.' + str(fmla)) return co.Concept(name, vs, fmla)
def create_isolate(iso,mod = None,**kwargs): mod = mod or im.module # check all mixin declarations for name,mixins in mod.mixins.iteritems(): for mixin in mixins: with ASTContext(mixins): action1,action2 = (lookup_action(mixin,mod,a.relname) for a in mixin.args) # check all the delagate declarations for dl in mod.delegates: lookup_action(dl.args[0],mod,dl.delegated()) if dl.delegee() and dl.delegee() not in mod.hierarchy: raise iu.IvyError(dl.args[1],"{} is not a module instance".format(name)) # Determine the mixin order (as a side effect on module.mixins) get_mixin_order(iso,mod) # Construct an isolate if iso: isolate_component(mod,iso) else: # apply all the mixins in no particular order for name,mixins in mod.mixins.iteritems(): for mixin in mixins: action1,action2 = (lookup_action(mixin,mod,a.relname) for a in mixin.args) mixed = ia.apply_mixin(mixin,action1,action2) mod.actions[mixin.args[1].relname] = mixed # find the globally exported actions (all if none specified, for compat) if mod.exports: mod.public_actions.clear() for e in mod.exports: if not e.scope(): # global export mod.public_actions.add(e.exported()) else: for a in mod.actions: mod.public_actions.add(a) # Create one big external action if requested ext = kwargs['ext'] if 'ext' in kwargs else ext_action.get() if ext is not None: ext_acts = [mod.actions[x] for x in sorted(mod.public_actions)] ext_act = ia.EnvAction(*ext_acts) mod.public_actions.add(ext); mod.actions[ext] = ext_act; # Check native interpretations of symbols slv.check_compat() # Make concept spaces from the conjecture for i,cax in enumerate(mod.labeled_conjs): fmla = cax.formula csname = 'conjecture:'+ str(i) variables = list(lu.used_variables_ast(fmla)) sort = ivy_logic.RelationSort([v.sort for v in variables]) sym = ivy_logic.Symbol(csname,sort) space = ics.NamedSpace(ivy_logic.Literal(0,fmla)) mod.concept_spaces.append((sym(*variables),space)) # ith.check_theory() if show_compiled.get(): for x,y in mod.actions.iteritems(): print iu.pretty("action {} = {}".format(x,y))
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 concept_from_formula(fmla,vs = None): if vs is None: vs = sorted(list(ilu.used_variables_ast(fmla)),key=str) name = (','.join(str(v) + ':' + str(v.sort) for v in vs) + '.' + str(fmla)) return co.Concept(name,vs,fmla)
def create_isolate(iso,mod = None,**kwargs): mod = mod or im.module # check all mixin declarations for name,mixins in mod.mixins.iteritems(): for mixin in mixins: with ASTContext(mixins): action1,action2 = (lookup_action(mixin,mod,a.relname) for a in mixin.args) # check all the delagate declarations for dl in mod.delegates: lookup_action(dl.args[0],mod,dl.delegated()) if dl.delegee() and dl.delegee() not in mod.hierarchy: raise iu.IvyError(dl.args[1],"{} is not a module instance".format(name)) # Determine the mixin order (as a side effect on module.mixins) get_mixin_order(iso,mod) # Construct an isolate if iso: isolate_component(mod,iso) else: if mod.isolates: raise iu.IvyError(None,'no isolate specified on command line') # apply all the mixins in no particular order for name,mixins in mod.mixins.iteritems(): for mixin in mixins: action1,action2 = (lookup_action(mixin,mod,a.relname) for a in mixin.args) mixed = ia.apply_mixin(mixin,action1,action2) mod.actions[mixin.args[1].relname] = mixed # find the globally exported actions (all if none specified, for compat) if mod.exports: mod.public_actions.clear() for e in mod.exports: if not e.scope(): # global export mod.public_actions.add(e.exported()) else: for a in mod.actions: mod.public_actions.add(a) # Create one big external action if requested ext = kwargs['ext'] if 'ext' in kwargs else ext_action.get() if ext is not None: ext_acts = [mod.actions[x] for x in sorted(mod.public_actions)] ext_act = ia.EnvAction(*ext_acts) mod.public_actions.add(ext); mod.actions[ext] = ext_act; # Check native interpretations of symbols slv.check_compat() # Make concept spaces from the conjecture for i,cax in enumerate(mod.labeled_conjs): fmla = cax.formula csname = 'conjecture:'+ str(i) variables = list(lu.used_variables_ast(fmla)) sort = ivy_logic.RelationSort([v.sort for v in variables]) sym = ivy_logic.Symbol(csname,sort) space = ics.NamedSpace(ivy_logic.Literal(0,fmla)) mod.concept_spaces.append((sym(*variables),space)) ith.check_theory() if show_compiled.get(): for x,y in mod.actions.iteritems(): print iu.pretty("action {} = {}".format(x,y))