def mk_variant_assign_clauses(lhs, rhs): n = lhs.rep new_n = new(n) args = lhs.args dlhs = new_n(*sym_placeholders(n)) vs = dlhs.args eqs = [ eq_atom(v, a) for (v, a) in zip(vs, args) if not isinstance(a, Variable) ] rn = dict((a.rep, v) for v, a in zip(vs, args) if isinstance(a, Variable)) drhs = substitute_ast(rhs, rn) nondet = n.suffix("_nd").skolem() if eqs: nondet = Ite(And(*eqs), nondet, n(*dlhs.args)) lsort, rsort = lhs.sort, rhs.sort fmlas = [ Iff( pto(lsort, rsort)(dlhs, Variable('X', rsort)), Equals(Variable('X', rsort), drhs)) ] for s in ivy_module.module.variants[lsort.name]: if s != rsort: fmlas.append(Not(pto(lsort, s)(dlhs, Variable('X', s)))) new_clauses = Clauses(fmlas, [Definition(dlhs, nondet)]) return new_clauses
def concept_label(self,concept): fmla = concept.formula if len(concept.variables) == 1: v = concept.variables[0] if can_abbreviate_formula(v,fmla): res = il.fmla_to_str_ambiguous(ilu.substitute_ast(fmla,{v.rep:Variable('',v.sort)})) return res.replace(' ','').replace('()','') return str(fmla)
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) 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)) new_n = new(n) args = lhs.args dlhs = new_n(*sym_placeholders(n)) vs = dlhs.args eqs = [ eq_atom(v, a) for (v, a) in zip(vs, args) if not isinstance(a, Variable) ] rn = dict( (a.rep, v) for v, a in zip(vs, args) if isinstance(a, Variable)) drhs = substitute_ast(rhs, rn) if eqs: drhs = Ite(And(*eqs), drhs, n(*dlhs.args)) new_clauses = Clauses([], [Definition(dlhs, drhs)]) # print "assign new_clauses = {}".format(new_clauses) return ([n], new_clauses, false_clauses())
def concept_label(self, concept): fmla = concept.formula if len(concept.variables) == 1: v = concept.variables[0] if can_abbreviate_formula(v, fmla): res = il.fmla_to_str_ambiguous( ilu.substitute_ast(fmla, {v.rep: Variable('', v.sort)})) return res.replace(' ', '').replace('()', '') return str(fmla)
def emit_derived(header, impl, df, classname): name = df.defines().name sort = df.defines().sort retval = il.Symbol("ret:val", sort) vs = df.args[0].args ps = [ilu.var_to_skolem('p:', v) for v in vs] mp = dict(zip(vs, ps)) rhs = ilu.substitute_ast(df.args[1], mp) action = ia.AssignAction(retval, rhs) action.formal_params = ps action.formal_returns = [retval] emit_some_action(header, impl, name, action, classname)
def emit_derived(header,impl,df,classname): name = df.defines().name sort = df.defines().sort retval = il.Symbol("ret:val",sort) vs = df.args[0].args ps = [ilu.var_to_skolem('p:',v) for v in vs] mp = dict(zip(vs,ps)) rhs = ilu.substitute_ast(df.args[1],mp) action = ia.AssignAction(retval,rhs) action.formal_params = ps action.formal_returns = [retval] emit_some_action(header,impl,name,action,classname)
def mk_assign_clauses(lhs,rhs): n = lhs.rep new_n = new(n) args = lhs.args dlhs = new_n(*sym_placeholders(n)) vs = dlhs.args eqs = [eq_atom(v,a) for (v,a) in zip(vs,args) if not isinstance(a,Variable)] rn = dict((a.rep,v) for v,a in zip(vs,args) if isinstance(a,Variable)) drhs = substitute_ast(rhs,rn) if eqs: drhs = Ite(And(*eqs),drhs,n(*dlhs.args)) new_clauses = Clauses([],[Definition(dlhs,drhs)]) return new_clauses
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) 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)) new_n = new(n) args = lhs.args dlhs = new_n(*sym_placeholders(n)) vs = dlhs.args eqs = [eq_atom(v, a) for (v, a) in zip(vs, args) if not isinstance(a, Variable)] rn = dict((a.rep, v) for v, a in zip(vs, args) if isinstance(a, Variable)) drhs = substitute_ast(rhs, rn) if eqs: drhs = Ite(And(*eqs), drhs, n(*dlhs.args)) new_clauses = Clauses([], [Definition(dlhs, drhs)]) # print "assign new_clauses = {}".format(new_clauses) return ([n], new_clauses, false_clauses())
def property_tactic(self, decls, proof): cut = proof.args[0] goal = decls[0] subgoal = goal_subst(goal, cut, cut.lineno) lhs = proof.args[1] if not isinstance(lhs, ia.NoneAST): fmla = il.drop_universals(cut.formula) if not il.is_exists(fmla) or len(fmla.variables) != 1: raise IvyError(proof, 'property is not existential') evar = list(fmla.variables)[0] rng = evar.sort vmap = dict((x.name, x) for x in lu.variables_ast(fmla)) used = set() args = lhs.args targs = [] for a in args: if a.name in used: raise IvyError(lhs, 'repeat parameter: {}'.format(a.name)) used.add(a.name) if a.name in vmap: v = vmap[a.name] targs.append(v) if not (il.is_topsort(a.sort) or a.sort != v.sort): raise IvyError(lhs, 'bad sort for {}'.format(a.name)) else: if il.is_topsort(a.sort): raise IvyError( lhs, 'cannot infer sort for {}'.format(a.name)) targs.append(a) for x in vmap: if x not in used: raise IvyError( lhs, '{} must be a parameter of {}'.format(x, lhs.rep)) dom = [x.sort for x in targs] sym = il.Symbol(lhs.rep, il.FuncConstSort(*(dom + [rng]))) if sym in self.stale or sym in goal_defns(goal): raise iu.IvyError(lhs, '{} is not fresh'.format(sym)) term = sym(*targs) if targs else sym fmla = lu.substitute_ast(fmla.body, {evar.name: term}) cut = clone_goal(cut, [], fmla) goal = goal_add_prem(goal, ia.ConstantDecl(sym), goal.lineno) return [goal_add_prem(goal, cut, cut.lineno)] + decls[1:] + [subgoal]
def transform_defn_match(prob): """ Transform a problem of matching definitions to a problem of matching the right-hand sides. Requires prob.inst is a definition. """ schema, conc, decl, freesyms = prob.schema, prob.pat, prob.inst, prob.freesyms if not (isinstance(decl, il.Definition) and isinstance(conc, il.Definition)): return prob declsym = decl.defines() concsym = conc.defines() # dmatch = match(conc.lhs(),decl.lhs(),freesyms) # if dmatch is None: # print "left-hand sides didn't match: {}, {}".format(conc.lhs(),decl.lhs()) # return None declargs = decl.lhs().args concargs = conc.lhs().args if len(declargs) < len(concargs): return None declrhs = decl.rhs() concrhs = conc.rhs() vmap = dict((x.name, y.resort(x.sort)) for x, y in zip(concargs, declargs)) concrhs = lu.substitute_ast(concrhs, vmap) dmatch = {concsym: declsym} for x, y in zip(func_sorts(concsym), func_sorts(declsym)): if x in freesyms: if x in dmatch and dmatch[x] != y: print "lhs sorts didn't match: {}, {}".format(x, y) return None dmatch[x] = y else: if x != y: print "lhs sorts didn't match: {}, {}".format(x, y) return None concrhs = apply_match(dmatch, concrhs) freesyms = apply_match_freesyms(dmatch, freesyms) freesyms = [x for x in freesyms if x not in concargs] constants = set(x for x in prob.constants if x not in declargs) vvmap = dict((x, y.resort(x.sort)) for x, y in zip(concargs, declargs)) schema = apply_match_goal(vvmap, schema, apply_match_alt) schema = apply_match_goal(dmatch, schema, apply_match_alt) return MatchProblem(schema, concrhs, declrhs, freesyms, constants)
def transform_defn_match(prob): """ Transform a problem of matching definitions to a problem of matching the right-hand sides. Requires prob.inst is a definition. """ conc,decl,freesyms = prob.pat,prob.inst,prob.freesyms if not(isinstance(decl,il.Definition) and isinstance(conc,il.Definition)): return prob declsym = decl.defines() concsym = conc.defines() # dmatch = match(conc.lhs(),decl.lhs(),freesyms) # if dmatch is None: # print "left-hand sides didn't match: {}, {}".format(conc.lhs(),decl.lhs()) # return None declargs = decl.lhs().args concargs = conc.lhs().args if len(declargs) < len(concargs): return None declrhs = decl.rhs() concrhs = conc.rhs() vmap = dict((x.name,y.resort(x.sort)) for x,y in zip(concargs,declargs)) concrhs = lu.substitute_ast(concrhs,vmap) dmatch = {concsym:declsym} for x,y in zip(func_sorts(concsym),func_sorts(declsym)): if x in freesyms: if x in dmatch and dmatch[x] != y: print "lhs sorts didn't match: {}, {}".format(x,y) return None dmatch[x] = y else: if x != y: print "lhs sorts didn't match: {}, {}".format(x,y) return None concrhs = apply_match(dmatch,concrhs) freesyms = apply_match_freesyms(dmatch,freesyms) freesyms = [x for x in freesyms if x not in concargs] constants = set(x for x in prob.constants if x not in declargs) return MatchProblem(concrhs,declrhs,freesyms,constants)
def emit_tick(header, impl, classname): global indent_level indent_level += 1 indent(header) header.append('void __tick(int timeout);\n') indent_level -= 1 indent(impl) impl.append('void ' + classname + '::__tick(int __timeout){\n') indent_level += 1 rely_map = defaultdict(list) for df in im.module.rely: key = df.args[0] if isinstance(df, il.Implies) else df rely_map[key.rep].append(df) for df in im.module.progress: vs = list(lu.free_variables(df.args[0])) open_loop(impl, vs) code = [] indent(code) df.args[0].emit(impl, code) code.append(' = ') df.args[1].emit(impl, code) code.append(' ? 0 : ') df.args[0].emit(impl, code) code.append(' + 1;\n') impl.extend(code) close_loop(impl, vs) for df in im.module.progress: if any(not isinstance(r, il.Implies) for r in rely_map[df.defines()]): continue vs = list(lu.free_variables(df.args[0])) open_loop(impl, vs) maxt = new_temp(impl) indent(impl) impl.append(maxt + ' = 0;\n') for r in rely_map[df.defines()]: if not isinstance(r, il.Implies): continue rvs = list(lu.free_variables(r.args[0])) assert len(rvs) == len(vs) subs = dict(zip(rvs, vs)) ## TRICKY: If there are any free variables on rhs of ## rely not occuring on left, we must prevent their capture ## by substitution xvs = set(lu.free_variables(r.args[1])) xvs = xvs - set(rvs) for xv in xvs: subs[xv.name] = xv.rename(xv.name + '__') xvs = [subs[xv.name] for xv in xvs] e = ilu.substitute_ast(r.args[1], subs) open_loop(impl, xvs) indent(impl) impl.append('{} = std::max({},'.format(maxt, maxt)) e.emit(impl, impl) impl.append(');\n') close_loop(impl, xvs) indent(impl) impl.append('if (' + maxt + ' > __timeout)\n ') indent(impl) df.args[0].emit(impl, impl) impl.append(' = 0;\n') indent(impl) impl.append('ivy_check_progress(') df.args[0].emit(impl, impl) impl.append(',{});\n'.format(maxt)) close_loop(impl, vs) indent_level -= 1 indent(impl) impl.append('}\n')
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 emit_tick(header,impl,classname): global indent_level indent_level += 1 indent(header) header.append('void __tick(int timeout);\n') indent_level -= 1 indent(impl) impl.append('void ' + classname + '::__tick(int __timeout){\n') indent_level += 1 rely_map = defaultdict(list) for df in im.module.rely: key = df.args[0] if isinstance(df,il.Implies) else df rely_map[key.rep].append(df) for df in im.module.progress: vs = list(lu.free_variables(df.args[0])) open_loop(impl,vs) code = [] indent(code) df.args[0].emit(impl,code) code.append(' = ') df.args[1].emit(impl,code) code.append(' ? 0 : ') df.args[0].emit(impl,code) code.append(' + 1;\n') impl.extend(code) close_loop(impl,vs) for df in im.module.progress: if any(not isinstance(r,il.Implies) for r in rely_map[df.defines()]): continue vs = list(lu.free_variables(df.args[0])) open_loop(impl,vs) maxt = new_temp(impl) indent(impl) impl.append(maxt + ' = 0;\n') for r in rely_map[df.defines()]: if not isinstance(r,il.Implies): continue rvs = list(lu.free_variables(r.args[0])) assert len(rvs) == len(vs) subs = dict(zip(rvs,vs)) ## TRICKY: If there are any free variables on rhs of ## rely not occuring on left, we must prevent their capture ## by substitution xvs = set(lu.free_variables(r.args[1])) xvs = xvs - set(rvs) for xv in xvs: subs[xv.name] = xv.rename(xv.name + '__') xvs = [subs[xv.name] for xv in xvs] e = ilu.substitute_ast(r.args[1],subs) open_loop(impl,xvs) indent(impl) impl.append('{} = std::max({},'.format(maxt,maxt)) e.emit(impl,impl) impl.append(');\n') close_loop(impl,xvs) indent(impl) impl.append('if (' + maxt + ' > __timeout)\n ') indent(impl) df.args[0].emit(impl,impl) impl.append(' = 0;\n') indent(impl) impl.append('ivy_check_progress(') df.args[0].emit(impl,impl) impl.append(',{});\n'.format(maxt)) close_loop(impl,vs) indent_level -= 1 indent(impl) impl.append('}\n')