Exemplo n.º 1
0
def apply_conj_proofs(mod):
    # Apply any proof tactics to the conjs to get the conj_subgoals.

    pc = ivy_proof.ProofChecker(mod.labeled_axioms + mod.assumed_invariants,
                                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)
            subgoals = map(ivy_compiler.theorem_to_property, subgoals)
            conjs.extend(subgoals)
        else:
            conjs.append(lf)
    mod.conj_subgoals = conjs
Exemplo n.º 2
0
def check_temporals():
    mod = im.module
    props = mod.labeled_props
    pmap = dict((prop.id, p) for prop, p in mod.proofs)
    pc = ivy_proof.ProofChecker(mod.labeled_axioms + mod.assumed_invariants,
                                mod.definitions, mod.schemata)
    for prop in props:
        print '\n    The following temporal property is being proved:\n'
        print pretty_lf(prop)
        if prop.temporal:
            proof = pmap.get(prop.id, None)
            model = itmp.normal_program_from_module(im.module)
            subgoal = prop.clone(
                [prop.args[0],
                 itmp.TemporalModels(model, prop.args[1])])
            subgoals = [subgoal]
            subgoals = pc.admit_proposition(prop, proof, subgoals)
            check_subgoals(subgoals)
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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()