def if_tactic(self,decls,proof): cond = proof.args[0] true_goal = ia.LabeledFormula(decls[0].label,il.Implies(cond,decls[0].formula)) true_goal.lineno = decls[0].lineno false_goal = ia.LabeledFormula(decls[0].label,il.Implies(il.Not(cond),decls[0].formula)) false_goal.lineno = decls[0].lineno return (attrib_goals(proof.args[1],self.apply_proof([true_goal],proof.args[1])) + attrib_goals(proof.args[2],self.apply_proof([false_goal],proof.args[2])) + decls[1:])
def match_schema(self,decl,proof): """ attempt to match a definition or property decl to a schema - decl is an ivy_ast.Definition or ivy_ast.Property - proof is an ivy_ast.SchemaInstantiation Returns a match or None """ schemaname = proof.schemaname() if schemaname not in self.schemata: raise ProofError(proof,"No schema {} exists".format(schemaname)) schema = self.schemata[schemaname] schema = transform_defn_schema(schema,decl) prob = match_problem(schema,decl) prob = transform_defn_match(prob) pmatch = compile_match(proof,prob,schemaname) prob.pat = apply_match_alt(pmatch,prob.pat) fomatch = fo_match(prob.pat,prob.inst,prob.freesyms,prob.constants) if fomatch is not None: prob.pat = apply_match(fomatch,prob.pat) prob.freesyms = apply_match_freesyms(fomatch,prob.freesyms) res = match(prob.pat,prob.inst,prob.freesyms,prob.constants) # show_match(res) if res is not None: subgoals = [] for x in schema.prems(): if isinstance(x,ia.LabeledFormula): fmla = apply_match_alt(remove_vars_match(pmatch,x.formula),x.formula) fmla = apply_match(remove_vars_match(fomatch,fmla),fmla) fmla = apply_match(remove_vars_match(res,fmla),fmla) g = ia.LabeledFormula(x.label,fmla) subgoals.append(g) return subgoals return None
def learnInv(mod): print "\n" * 2 print "<plearn> Directed to learning Algorithm" global silent, module, numVarFS, featureset silent = True updatenvi(mod) module = mod while True: print "Checking Inductiveness of the Invariant" maxunv, isInvInd = icheck.isInvInductive(mod) print "Invariant is{} Inductive\n".format('' if isInvInd else ' NOT') if isInvInd: # its Inductive so nothing to do silent = False checkInitialCond(mod) break # testfunc(mod) for actname in sorted(mod.public_actions): print "learning Invariant for action {}".format(actname) clf = Classifier() # new classifier newInv = learnWeekestInv(mod, clf, actname) print "\n" * 2 print "<plearn> new Invariant:", newInv a = raw_input('new Invariant learned, press enter to continue') print "\n" * 2 numVarFS = {} # resetting numVarFS featureset = [] # resetting featuerset if newInv != true_clauses(): lf = ivy_ast.LabeledFormula(*[ ivy_ast.Atom('learnedInv' + actname), logic.And(*newInv.fmlas) ]) mod.labeled_conjs.append( lf) # modifying mod and module, obj are copied by refr. updatenvi(mod) # takes care of numVarInv
def let_tactic(self,decls,proof): cond = il.And(*[il.Equals(x,y) for x,y in proof.args]) subgoal = ia.LabeledFormula(decls[0].label,il.Implies(cond,decls[0].formula)) if not hasattr(decls[0],'lineno'): print 'has no line number: {}'.format(decls[0]) exit(1) subgoal.lineno = decls[0].lineno return attrib_goals(proof,[subgoal]) + decls[1:]
def expand_schemata(mod,sort_constants,funs): match = Match() res = [] for s in mod.sig.sorts.values(): if not il.is_function_sort(s): match.add(s,s) for name,lf in mod.schemata.iteritems(): schema = lf.formula if any(name.startswith(pref) for pref in ['rec[','lep[','ind[']): continue conc = schema.args[-1] for m in match_schema_prems(list(schema.args[:-1]),sort_constants,funs,match): # iu.dbg('str_map(m)') # iu.dbg('conc') inst = apply_match(m,conc) res.append(ivy_ast.LabeledFormula(ivy_ast.Atom(name),inst)) return res
def make_goal(lineno, label, prems, conc): res = ia.LabeledFormula( label, ia.SchemaBody(*(prems + [conc])) if prems else conc) res.lineno = lineno return res
def let_tactic(self, decls, proof): cond = il.And(*[il.Equals(x, y) for x, y in proof.args]) subgoal = ia.LabeledFormula(decls[0].label, il.Implies(cond, decls[0].formula)) subgoal.lineno = decls[0].lineno return attrib_goals(proof, [subgoal]) + decls[1:]
def l2s(mod, temporal_goal): # modify mod in place # module pass helper funciton def mod_pass(transform): mod.labeled_conjs = [transform(x) for x in mod.labeled_conjs] # TODO: what about axioms and properties? for a in mod.public_actions: action = mod.actions[a] new_action = transform(action) new_action.lineno = action.lineno new_action.formal_params = action.formal_params new_action.formal_returns = action.formal_returns mod.actions[a] = new_action mod.initializers = [(x, transform(y)) for x, y in mod.initializers] l2s_waiting = lg.Const('l2s_waiting', lg.Boolean) l2s_frozen = lg.Const('l2s_frozen', lg.Boolean) l2s_saved = lg.Const('l2s_saved', lg.Boolean) l2s_error = lg.Const('l2s_error', lg.Boolean) l2s_d = lambda sort: lg.Const('l2s_d', lg.FunctionSort(sort, lg.Boolean)) l2s_a = lambda sort: lg.Const('l2s_a', lg.FunctionSort(sort, lg.Boolean)) l2s_w = lambda vs, t: lg.NamedBinder('l2s_w', vs, t) l2s_s = lambda vs, t: lg.NamedBinder('l2s_s', vs, t) l2s_g = lambda vs, t: lg.NamedBinder('l2s_g', vs, t) old_l2s_g = lambda vs, t: lg.NamedBinder('old_l2s_g', vs, t) # add conjectures about monitor state conjs = [ lg.Or(l2s_waiting, l2s_frozen, l2s_saved), lg.Or(lg.Not(l2s_waiting), lg.Not(l2s_frozen)), lg.Or(lg.Not(l2s_waiting), lg.Not(l2s_saved)), lg.Or(lg.Not(l2s_frozen), lg.Not(l2s_saved)), ] for f in conjs: c = ast.LabeledFormula(ast.Atom('l2s_internal'), f) c.lineno = temporal_goal.lineno mod.labeled_conjs.append(c) # add conjecture that we are not in the error state (this is # instead of using an assertion. see below) c = ast.LabeledFormula(ast.Atom('not_l2s_error'), lg.Not(l2s_error)) c.lineno = temporal_goal.lineno mod.labeled_conjs.append(c) #print ilu.used_symbols_asts(mod.labeled_conjs) #print '='*40 #print list(ilu.named_binders_asts(mod.labeled_conjs)) # some normalization # We first convert all temporal operators to named binders, so # it's possible to normalize them. Otherwise we won't have the # connection betweel (globally p(X)) and (globally p(Y)). Note # that we replace them even inside named binders. l2s_gs = set() def _l2s_g(vs, t): vs = tuple(vs) res = l2s_g(vs, t) l2s_gs.add((vs, t)) return res replace_temporals_by_l2s_g = lambda ast: ilu.replace_temporals_by_named_binder_g_ast( ast, _l2s_g) mod_pass(replace_temporals_by_l2s_g) not_temporal_goal = replace_temporals_by_l2s_g( lg.Not(temporal_goal.formula)) if debug.get(): print "=" * 80 + "\nafter replace_temporals_by_named_binder_g_ast" + "\n" * 3 print "=" * 80 + "\nl2s_gs:" for vs, t in sorted(l2s_gs): print vs, t print "=" * 80 + "\n" * 3 print_module(mod) print "=" * 80 + "\n" * 3 # now we normalize all named binders mod_pass(ilu.normalize_named_binders) if debug.get(): print "=" * 80 + "\nafter normalize_named_binders" + "\n" * 3 print_module(mod) print "=" * 80 + "\n" * 3 # TODO: what about normalizing temporal_goal? - temporal_goal # should not contain any named binders except for temporal # properties, so it is normalized by construction # construct the monitor related building blocks uninterpreted_sorts = [ s for s in mod.sig.sorts.values() if type(s) is lg.UninterpretedSort ] reset_a = [ AssignAction(l2s_a(s)(v), l2s_d(s)(v)) for s in uninterpreted_sorts for v in [lg.Var('X', s)] ] add_consts_to_d = [ AssignAction(l2s_d(s)(c), lg.true) for s in uninterpreted_sorts for c in mod.sig.symbols.values() if c.sort == s ] # TODO: maybe add all ground terms, not just consts (if stratified) # TODO: add conjectures that constants are in d and a # figure out which l2s_w and l2s_s are used in conjectures named_binders_conjs = defaultdict( list) # dict mapping names to lists of (vars, body) for b in ilu.named_binders_asts(mod.labeled_conjs): named_binders_conjs[b.name].append((b.variables, b.body)) named_binders_conjs = defaultdict( list, ((k, sorted(list(set(v)))) for k, v in named_binders_conjs.iteritems())) to_wait = [ ] # list of (variables, term) corresponding to l2s_w in conjectures to_wait += named_binders_conjs['l2s_w'] to_save = [ ] # list of (variables, term) corresponding to l2s_s in conjectures to_save += named_binders_conjs['l2s_s'] if debug.get(): print "=" * 40 + "\nto_wait:\n" for vs, t in to_wait: print vs, t # print list(ilu.variables_ast(t)) == list(vs) # print print "=" * 40 save_state = [AssignAction(l2s_s(vs, t)(*vs), t) for vs, t in to_save] done_waiting = [forall(vs, lg.Not(l2s_w(vs, t)(*vs))) for vs, t in to_wait] reset_w = [ AssignAction( l2s_w(vs, t)(*vs), lg.And(*(l2s_d(v.sort)(v) for v in vs))) for vs, t in to_wait ] update_w = [ AssignAction( l2s_w(vs, t)(*vs), lg.And( l2s_w(vs, t)(*vs), lg.Not(t), replace_temporals_by_l2s_g(lg.Not(lg.Globally(ilu.negate(t))))) # ($l2s_w. phi) waits until ( phi | globally ~phi), but # ($l2s_w. ~phi) waits until (~phi | globally phi) (i.e., we avoid "globally ~~phi" here) # note this adds to l2s_gs ) for vs, t in to_wait ] if debug.get(): print "=" * 40 + "\nupdate_w:\n" for x in update_w: print x print print "=" * 40 fair_cycle = [l2s_saved] fair_cycle += done_waiting # projection of relations fair_cycle += [ lg.ForAll( vs, lg.Implies(lg.And(*(l2s_a(v.sort)(v) for v in vs)), lg.Iff(l2s_s(vs, t)(*vs), t))) if len(vs) > 0 else lg.Iff(l2s_s(vs, t), t) for vs, t in to_save if (t.sort == lg.Boolean or isinstance(t.sort, lg.FunctionSort) and t.sort.range == lg.Boolean) ] # projection of functions and constants fair_cycle += [ forall( vs, lg.Implies( lg.And(*([l2s_a(v.sort)(v) for v in vs] + [ lg.Or(l2s_a(t.sort)(l2s_s(vs, t)(*vs)), l2s_a(t.sort)(t)) ])), lg.Eq(l2s_s(vs, t)(*vs), t))) for vs, t in to_save if (isinstance(t.sort, lg.UninterpretedSort) or isinstance(t.sort, lg.FunctionSort) and isinstance(t.sort.range, lg.UninterpretedSort)) ] if debug.get(): print "=" * 40 + "\nfair_cycle:\n" for x in fair_cycle: print x print print "=" * 40 # TODO: figure out why AssertAction doesn't work properly def assert_no_fair_cycle(a): # comment and uncomment the following lines to debug: # res = AssertAction(lg.Not(lg.And(*fair_cycle))) # res = AssertAction(lg.false) # res.lineno = temporal_goal.lineno # res.lineno = a.lineno res = AssignAction(l2s_error, lg.And(*fair_cycle)) return res monitor_edge = lambda s1, s2: [ AssumeAction(s1), AssignAction(s1, lg.false), AssignAction(s2, lg.true), ] change_monitor_state = [ ChoiceAction( # waiting -> frozen Sequence(*(monitor_edge(l2s_waiting, l2s_frozen) + [AssumeAction(x) for x in done_waiting] + reset_a)), # frozen -> saved Sequence(*(monitor_edge(l2s_frozen, l2s_saved) + save_state + reset_w)), # stay in same state (self edge) Sequence(), ) ] # tableau construction to_g = [] # list of (variables, formula) to_g += sorted(list(l2s_gs)) if debug.get(): print '=' * 40 + "\nto_g:\n" for vs, t in to_g: print vs, t, '\n' print '=' * 40 assume_g_axioms = [ AssumeAction(forall(vs, lg.Implies(l2s_g(vs, t)(*vs), t))) for vs, t in to_g ] update_g = [ a for vs, t in to_g for a in [ HavocAction(l2s_g(vs, t)(*vs)), AssumeAction( forall(vs, lg.Implies( old_l2s_g(vs, t)(*vs), l2s_g(vs, t)(*vs)))), AssumeAction( forall( vs, lg.Implies(lg.And(lg.Not(old_l2s_g(vs, t)( *vs)), t), lg.Not(l2s_g(vs, t)(*vs))))), ] ] # now patch the module actions with monitor and tableau if debug.get(): print "public_actions:", mod.public_actions for a in mod.public_actions: action = mod.actions[a] add_params_to_d = [ AssignAction(l2s_d(p.sort)(p), lg.true) for p in action.formal_params ] new_action = concat_actions(*( # TODO: check this with Sharon assume_g_axioms + change_monitor_state + add_params_to_d + update_g + [action] + assume_g_axioms + add_consts_to_d + update_w + [assert_no_fair_cycle(action)])) new_action.lineno = action.lineno new_action.formal_params = action.formal_params new_action.formal_returns = action.formal_returns mod.actions[a] = new_action l2s_init = [ AssignAction(l2s_waiting, lg.true), AssignAction(l2s_frozen, lg.false), AssignAction(l2s_saved, lg.false), AssignAction(l2s_error, lg.false), ] l2s_init += add_consts_to_d l2s_init += reset_w l2s_init += assume_g_axioms l2s_init += [AssumeAction(not_temporal_goal)] mod.initializers.append(('l2s_init', Sequence(*l2s_init))) if debug.get(): print "=" * 80 + "\nafter patching actions" + "\n" * 3 print_module(mod) print "=" * 80 + "\n" * 3 # now replace all named binders by fresh relations named_binders = defaultdict( list) # dict mapping names to lists of (vars, body) for b in ilu.named_binders_asts( chain( mod.labeled_conjs, mod.actions.values(), (y for x, y in mod.initializers), )): named_binders[b.name].append(b) # sort named binders according to a consistent order named_binders = defaultdict( list, ((k, list( sorted( set(v), key=lambda x: (len(x.variables), str(x.variables), str(x.body)), ))) for k, v in named_binders.iteritems())) # make sure old_l2s_g is consistent with l2s_g, so that # old_l2s_g_X is really old l2s_g_X after the substitution assert len(named_binders['l2s_g']) == len(named_binders['old_l2s_g']) assert named_binders['old_l2s_g'] == [ lg.NamedBinder('old_l2s_g', b.variables, b.body) for b in named_binders['l2s_g'] ] subs = dict((b, lg.Const('{}_{}'.format(k, i), b.sort)) for k, v in named_binders.iteritems() for i, b in enumerate(v)) if debug.get(): print "=" * 80 + "\nsubs:" + "\n" * 3 for k in sorted(named_binders.keys()): v = named_binders[k] for i, b in enumerate(v): print '{}_{}'.format(k, i), ' : ', b print "=" * 80 + "\n" * 3 mod_pass(lambda ast: ilu.replace_named_binders_ast(ast, subs)) if debug.get(): print "=" * 80 + "\nafter replace_named_binders" + "\n" * 3 print_module(mod) print "=" * 80 + "\n" * 3
def check_isolate(): mod = im.module if mod.isolate_proof is not None: pc = ivy_proof.ProofChecker( mod.labeled_axioms + mod.assumed_invariants, mod.definitions, mod.schemata) model = itmp.normal_program_from_module(im.module) prop = ivy_ast.LabeledFormula(ivy_ast.Atom('safety'), lg.And()) subgoal = ivy_ast.LabeledFormula(ivy_ast.Atom('safety'), itmp.TemporalModels(model, lg.And())) # print 'subgoal = {}'.format(subgoal) subgoals = [subgoal] subgoals = pc.admit_proposition(prop, mod.isolate_proof, subgoals) check_subgoals(subgoals) return ifc.check_fragment() with im.module.theory_context(): global check_lineno check_lineno = act.checked_assert.get() if check_lineno == "": check_lineno = None # print 'check_lineno: {}'.format(check_lineno) check = not opt_summary.get() subgoalmap = dict((x.id, y) for x, y in im.module.subgoals) axioms = [m for m in mod.labeled_axioms if m.id not in subgoalmap] schema_instances = [ m for m in mod.labeled_axioms if m.id in subgoalmap ] if axioms: print "\n The following properties are assumed as axioms:" for lf in axioms: print pretty_lf(lf) if mod.definitions: print "\n The following definitions are used:" for lf in mod.definitions: print pretty_lf(lf) if (mod.labeled_props or schema_instances) and not checked_action.get(): print "\n The following properties are to be checked:" if check: for lf in schema_instances: print pretty_lf(lf) + " [proved by axiom schema]" ag = ivy_art.AnalysisGraph() clauses1 = lut.true_clauses(annot=act.EmptyAnnotation()) pre = itp.State(value=clauses1) props = [x for x in im.module.labeled_props if not x.temporal] props = [ p for p in props if not (p.id in subgoalmap and p.explicit) ] fcs = ([(ConjAssumer if prop.assumed or prop.id in subgoalmap else ConjChecker)(prop) for prop in props]) check_fcs_in_state(mod, ag, pre, fcs) else: for lf in schema_instances + mod.labeled_props: print pretty_lf(lf) # after checking properties, make them axioms, except temporals im.module.labeled_axioms.extend(p for p in im.module.labeled_props if not p.temporal) im.module.update_theory() if mod.labeled_inits: print "\n The following properties are assumed initially:" for lf in mod.labeled_inits: print pretty_lf(lf) if mod.labeled_conjs: print "\n The inductive invariant consists of the following conjectures:" for lf in mod.labeled_conjs: print pretty_lf(lf) apply_conj_proofs(mod) if mod.isolate_info is not None and mod.isolate_info.implementations: print "\n The following action implementations are present:" for mixer, mixee, action in sorted( mod.isolate_info.implementations, key=lambda x: x[0]): print " {}implementation of {}".format( pretty_lineno(action), mixee) if mod.isolate_info is not None and mod.isolate_info.monitors: print "\n The following action monitors are present:" for mixer, mixee, action in sorted(mod.isolate_info.monitors, key=lambda x: x[0]): print " {}monitor of {}".format(pretty_lineno(action), mixee) # if mod.actions: # print "\n The following actions are present:" # for actname,action in sorted(mod.actions.iteritems()): # print " {}{}".format(pretty_lineno(action),actname) if mod.initializers: print "\n The following initializers are present:" for actname, action in sorted(mod.initializers, key=lambda x: x[0]): print " {}{}".format(pretty_lineno(action), actname) if mod.labeled_conjs and not checked_action.get(): print "\n Initialization must establish the invariant" if check: with itp.EvalContext(check=False): ag = ivy_art.AnalysisGraph(initializer=lambda x: None) check_conjs_in_state(mod, ag, ag.states[0]) else: print '' if mod.initializers: print "\n Any assertions in initializers must be checked", if check: ag = ivy_art.AnalysisGraph(initializer=lambda x: None) fail = itp.State(expr=itp.fail_expr(ag.states[0].expr)) check_safety_in_state(mod, ag, fail) checked_actions = get_checked_actions() if checked_actions and mod.labeled_conjs: print "\n The following set of external actions must preserve the invariant:" for actname in sorted(checked_actions): action = act.env_action(actname) print " {}{}".format(pretty_lineno(action), actname) if check: ag = ivy_art.AnalysisGraph() pre = itp.State() pre.clauses = get_conjs(mod) with itp.EvalContext(check=False): # don't check safety # post = ag.execute(action, pre, None, actname) post = ag.execute(action, pre) check_conjs_in_state(mod, ag, post, indent=12) else: print '' callgraph = defaultdict(list) for actname, action in mod.actions.iteritems(): for called_name in action.iter_calls(): callgraph[called_name].append(actname) some_assumps = False for actname, action in mod.actions.iteritems(): assumptions = [ sub for sub in action.iter_subactions() if isinstance(sub, act.AssumeAction) ] if assumptions: if not some_assumps: print "\n The following program assertions are treated as assumptions:" some_assumps = True callers = callgraph[actname] if actname in mod.public_actions: callers.append("the environment") prettyname = actname[4:] if actname.startswith( 'ext:') else actname prettycallers = [ c[4:] if c.startswith('ext:') else c for c in callers ] print " in action {} when called from {}:".format( prettyname, ','.join(prettycallers)) for sub in assumptions: print " {}assumption".format(pretty_lineno(sub)) tried = set() some_guarants = False for actname, action in mod.actions.iteritems(): guarantees = [ sub for sub in action.iter_subactions() if isinstance(sub, (act.AssertAction, act.Ranking)) ] if check_lineno is not None: guarantees = [ sub for sub in guarantees if sub.lineno == check_lineno ] if guarantees: if not some_guarants: print "\n The following program assertions are treated as guarantees:" some_guarants = True callers = callgraph[actname] if actname in mod.public_actions: callers.append("the environment") prettyname = actname[4:] if actname.startswith( 'ext:') else actname prettycallers = [ c[4:] if c.startswith('ext:') else c for c in callers ] print " in action {} when called from {}:".format( prettyname, ','.join(prettycallers)) roots = set(iu.reachable([actname], lambda x: callgraph[x])) for sub in guarantees: print " {}guarantee".format(pretty_lineno(sub)), if check and any( r in roots and (r, sub.lineno) not in tried for r in checked_actions): print_dots() old_checked_assert = act.checked_assert.get() act.checked_assert.value = sub.lineno some_failed = False for root in checked_actions: if root in roots: tried.add((root, sub.lineno)) action = act.env_action(root) ag = ivy_art.AnalysisGraph() pre = itp.State() pre.clauses = get_conjs(mod) with itp.EvalContext(check=False): post = ag.execute(action, prestate=pre) fail = itp.State(expr=itp.fail_expr(post.expr)) if not check_safety_in_state( mod, ag, fail, report_pass=False): some_failed = True break if not some_failed: print 'PASS' act.checked_assert.value = old_checked_assert else: print "" check_temporals()
def let_tactic(self,decls,proof): cond = il.And(*[il.Equals(x,y) for x,y in proof.args]) return [ia.LabeledFormula(decls[0].label, il.Implies(cond,decls[0].formula))] + decls[1:]