Esempio n. 1
0
 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
Esempio n. 2
0
 def __init__(self, clauses, model, vocab, top_level=True):
     art.AnalysisGraph.__init__(self)
     self.clauses = clauses
     self.model = model
     self.vocab = vocab
     mod_clauses = islv.clauses_model_to_clauses(clauses,
                                                 model=model,
                                                 numerals=True)
     self.eqs = defaultdict(list)
     for fmla in mod_clauses.fmlas:
         if lg.is_eq(fmla):
             lhs, rhs = fmla.args
             if lg.is_app(lhs):
                 self.eqs[lhs.rep].append(fmla)
         elif isinstance(fmla, lg.Not):
             app = fmla.args[0]
             if lg.is_app(app):
                 self.eqs[app.rep].append(lg.Equals(app, lg.Or()))
         else:
             if lg.is_app(fmla):
                 self.eqs[fmla.rep].append(lg.Equals(fmla, lg.And()))
     self.last_action = None
     self.sub = None
     self.returned = None
     self.top_level = top_level
Esempio n. 3
0
 def __init__(self, clauses, model, vocab):
     #        iu.dbg('clauses')
     self.clauses = clauses
     self.model = model
     self.vocab = vocab
     self.current = dict()
     mod_clauses = islv.clauses_model_to_clauses(clauses,
                                                 model=model,
                                                 numerals=True)
     #        iu.dbg('mod_clauses')
     self.eqs = defaultdict(list)
     for fmla in mod_clauses.fmlas:
         if lg.is_eq(fmla):
             lhs, rhs = fmla.args
             if lg.is_app(lhs):
                 self.eqs[lhs.rep].append(fmla)
         elif isinstance(fmla, lg.Not):
             app = fmla.args[0]
             if lg.is_app(app):
                 self.eqs[app.rep].append(lg.Equals(app, lg.Or()))
         else:
             if lg.is_app(fmla):
                 self.eqs[fmla.rep].append(lg.Equals(fmla, lg.And()))
     # for sym in vocab:
     #     if not itr.is_new(sym) and not itr.is_skolem(sym):
     #         self.show_sym(sym,sym)
     self.started = False
     self.renaming = dict()
     print
     print 'Trace follows...'
     print 80 * '*'
 def __init__(self, clauses, model, vocab, top_level=True):
     TraceBase.__init__(self)
     self.clauses = clauses
     self.model = model
     self.vocab = vocab
     self.top_level = top_level
     if clauses is not None:
         ignore = lambda s: islv.solver_name(s) == None
         mod_clauses = islv.clauses_model_to_clauses(clauses,
                                                     model=model,
                                                     numerals=True,
                                                     ignore=ignore)
         self.eqs = defaultdict(list)
         for fmla in mod_clauses.fmlas:
             if lg.is_eq(fmla):
                 lhs, rhs = fmla.args
                 if lg.is_app(lhs):
                     self.eqs[lhs.rep].append(fmla)
             elif isinstance(fmla, lg.Not):
                 app = fmla.args[0]
                 if lg.is_app(app):
                     self.eqs[app.rep].append(lg.Equals(app, lg.Or()))
             else:
                 if lg.is_app(fmla):
                     self.eqs[fmla.rep].append(lg.Equals(fmla, lg.And()))
Esempio n. 5
0
 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:]
Esempio n. 6
0
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()
Esempio n. 7
0
def get_truth(digits,idx,syms):
    if (len(digits) != len(syms)):
        badwit()
    digit = digits[idx]
    if digit == '0':
        return il.Or()
    elif digit == '1':
        return il.And()
    elif digit != 'x':
        badwit()
    return None
Esempio n. 8
0
def clone_normal(expr,args):
    if il.is_eq(expr):
        x,y = args
        if x == y:
            return il.And()
        to = term_ord(x,y)
#        print 'term_ord({},{}) = {}'.format(x,y,to)
        if to == 1:
            x,y = y,x
        return expr.clone([x,y])
    return expr.clone(args)
Esempio n. 9
0
 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:]
Esempio n. 10
0
def constant_from_z3(sort, c):
    if z3.is_true(c):
        return ivy_logic.And()
    if z3.is_false(c):
        return ivy_logic.Or()
    return ivy_logic.Constant(ivy_logic.Symbol(repr(c), sort))
Esempio n. 11
0
 def scenario(self, scen):
     init_tokens = set(p.rep for p in scen.args[0].args)
     transs_by_action = defaultdict(list)
     for tr in scen.args[1:]:
         transs_by_action[tr.args[2].args[1].args[0].rep].append(tr)
     for (place_name, lineno) in scen.places():
         sym = find_symbol(place_name)
         iname = place_name + '[init]'
         iact = AssignAction(
             sym,
             ivy_logic.And() if
             (place_name in init_tokens) else ivy_logic.Or())
         iact.formal_params = []
         iact.formal_returns = []
         iact.lineno = scen.lineno
         self.mod.actions[iname] = iact
         self.mixin(
             ivy_ast.MixinAfterDef(ivy_ast.Atom(iname),
                                   ivy_ast.Atom('init')))
     for actname, trs in transs_by_action.iteritems():
         choices = []
         params = None
         afters = []
         for tr in trs:
             scmix = tr.args[2]
             is_after = isinstance(scmix, ivy_ast.ScenarioAfterMixin)
             df = scmix.args[1]
             body = compile_action_def(df, self.mod.sig)
             seq = []
             if not is_after:
                 for p in tr.args[0].args:
                     seq.append(AssumeAction(find_symbol(p.rep)))
                 for p in tr.args[0].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.Or()))
                 for p in tr.args[1].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.And()))
                 seq.append(body)
                 seq = Sequence(*seq)
             else:
                 for p in tr.args[0].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.Or()))
                 for p in tr.args[1].args:
                     seq.append(
                         AssignAction(find_symbol(p.rep), ivy_logic.And()))
                 seq.append(body)
                 seq = Sequence(*seq)
                 seq = IfAction(
                     And(*[find_symbol(p.rep) for p in tr.args[0].args]),
                     seq)
             if params is None:
                 params = body.formal_params
                 returns = body.formal_returns
                 mixer = scmix.args[0]
                 mixee = scmix.args[1].args[0]
             else:
                 aparams = df.formal_params + df.formal_returns
                 subst = dict(zip(aparams, params + returns))
                 seq = substitute_constants_ast(seq, subst)
             seq.lineno = tr.lineno
             if not is_after:
                 choices.append(seq)
             else:
                 afters.append(seq)
         if choices:
             choice = BalancedChoice(choices)
             choice.lineno = choices[0].lineno
             choice.formal_params = params
             choice.formal_returns = returns
             self.mod.actions[mixer.rep] = choice
             self.mixin(ivy_ast.MixinBeforeDef(mixer, mixee))
         if afters:
             choice = Sequence(*afters)
             choice.lineno = afters[0].lineno
             choice.formal_params = params
             choice.formal_returns = returns
             self.mod.actions[mixer.rep] = choice
             self.mixin(ivy_ast.MixinAfterDef(mixer, mixee))
Esempio n. 12
0
 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:]
Esempio n. 13
0
def isolate_component(mod, isolate_name, extra_with=[], extra_strip=None):
    if isolate_name not in mod.isolates:
        raise iu.IvyError(None, "undefined isolate: {}".format(isolate_name))
    isolate = mod.isolates[isolate_name]
    verified = set(a.relname for a in (isolate.verified() + tuple(extra_with)))
    present = set(a.relname for a in isolate.present())
    present.update(verified)
    if not interpret_all_sorts:
        for type_name in list(ivy_logic.sig.interp):
            if not (type_name in present or any(
                    startswith_eq_some(itp.label.rep, present, mod)
                    for itp in mod.interps[type_name] if itp.label)):
                del ivy_logic.sig.interp[type_name]
    delegates = set(s.delegated() for s in mod.delegates if not s.delegee())
    delegated_to = dict(
        (s.delegated(), s.delegee()) for s in mod.delegates if s.delegee())
    derived = set(df.args[0].func.name for df in mod.concepts)
    for name in present:
        if (name not in mod.hierarchy and name not in ivy_logic.sig.sorts
                and name not in derived and name not in ivy_logic.sig.interp
                and name not in mod.actions
                and name not in ivy_logic.sig.symbols):
            raise iu.IvyError(
                None,
                "{} is not an object, action, sort, definition, or interpreted function"
                .format(name))

    impl_mixins = defaultdict(list)
    # delegate all the stub actions to their implementations
    global implementation_map
    implementation_map = {}
    for actname, ms in mod.mixins.iteritems():
        implements = [
            m for m in ms if isinstance(m, ivy_ast.MixinImplementDef)
        ]
        impl_mixins[actname].extend(implements)
        before_after = [
            m for m in ms if not isinstance(m, ivy_ast.MixinImplementDef)
        ]
        del ms[:]
        ms.extend(before_after)
        for m in implements:
            for foo in (m.mixee(), m.mixer()):
                if foo not in mod.actions:
                    raise IvyError(m, 'action {} not defined'.format(foo))
            action = mod.actions[m.mixee()]
            if not (isinstance(action, ia.Sequence) and len(action.args) == 0):
                raise IvyError(
                    m,
                    'multiple implementations of action {}'.format(m.mixee()))
            action = ia.apply_mixin(m, mod.actions[m.mixer()], action)
            mod.actions[m.mixee()] = action
            implementation_map[m.mixee()] = m.mixer()

    new_actions = {}
    use_mixin = lambda name: startswith_some(name, present, mod)
    mod_mixin = lambda m: m if startswith_some(name, verified, mod
                                               ) else m.prefix_calls('ext:')
    all_mixins = lambda m: True
    no_mixins = lambda m: False
    after_mixins = lambda m: isinstance(m, ivy_ast.MixinAfterDef)
    before_mixins = lambda m: isinstance(m, ivy_ast.MixinBeforeDef)
    delegated_to_verified = lambda n: n in delegated_to and startswith_eq_some(
        delegated_to[n], verified, mod)
    ext_assumes = lambda m: before_mixins(m) and not delegated_to_verified(
        m.mixer())
    int_assumes = lambda m: after_mixins(m) and not delegated_to_verified(
        m.mixer())
    ext_assumes_no_ver = lambda m: not delegated_to_verified(m.mixer())
    summarized_actions = set()
    for actname, action in mod.actions.iteritems():
        ver = startswith_eq_some(actname, verified, mod)
        pre = startswith_eq_some(actname, present, mod)
        if pre:
            if not ver:
                assert hasattr(action, 'lineno')
                assert hasattr(action, 'formal_params'), action
                ext_action = action.assert_to_assume().prefix_calls('ext:')
                assert hasattr(ext_action, 'lineno')
                assert hasattr(ext_action, 'formal_params'), ext_action
                if actname in delegates:
                    int_action = action.prefix_calls('ext:')
                    assert hasattr(int_action, 'lineno')
                    assert hasattr(int_action, 'formal_params'), int_action
                else:
                    int_action = ext_action
                    assert hasattr(int_action, 'lineno')
                    assert hasattr(int_action, 'formal_params'), int_action
            else:
                int_action = ext_action = action
                assert hasattr(int_action, 'lineno')
                assert hasattr(int_action, 'formal_params'), int_action
            # internal version of the action has mixins checked
            ea = no_mixins if ver else int_assumes
            new_actions[actname] = add_mixins(mod, actname, int_action, ea,
                                              use_mixin, lambda m: m)
            # external version of the action assumes mixins are ok, unless they
            # are delegated to a currently verified object
            ea = ext_assumes if ver else ext_assumes_no_ver
            new_action = add_mixins(mod, actname, ext_action, ea, use_mixin,
                                    mod_mixin)
            new_actions['ext:' + actname] = new_action
            # TODO: external version is public if action public *or* called from opaque
            # public_actions.add('ext:'+actname)
        else:
            # TODO: here must check that summarized action does not
            # have a call dependency on the isolated module
            summarized_actions.add(actname)
            action = summarize_action(action)
            new_actions[actname] = add_mixins(mod, actname, action,
                                              after_mixins, use_mixin,
                                              mod_mixin)
            new_actions['ext:' + actname] = add_mixins(mod, actname, action,
                                                       all_mixins, use_mixin,
                                                       mod_mixin)

    # figure out what is exported:
    exported = set()
    for e in mod.exports:
        if not e.scope() and startswith_eq_some(e.exported(), present,
                                                mod):  # global scope
            exported.add('ext:' + e.exported())
    for actname, action in mod.actions.iteritems():
        if not startswith_some(actname, present, mod):
            for c in action.iter_calls():
                if (startswith_some(c, present, mod) or any(
                        startswith_some(m.mixer(), present, mod)
                        for m in mod.mixins[c])):
                    exported.add('ext:' + c)
#    print "exported: {}".format(exported)

# We allow objects to reference any symbols in global scope, and
# we keep axioms declared in global scope. Because of the way
# thigs are named, this gives a different condition for keeping
# symbols and axioms (in particular, axioms in global scope have
# label None). Maybe this needs to be cleaned up.

    keep_sym = lambda name: (iu.ivy_compose_character not in name or
                             startswith_eq_some(name, present))

    keep_ax = lambda name: (name is None or startswith_eq_some(
        name.rep, present, mod))
    check_pr = lambda name: (name is None or startswith_eq_some(
        name.rep, verified, mod))

    prop_deps = get_prop_dependencies(mod)

    # filter the conjectures

    new_conjs = [c for c in mod.labeled_conjs if keep_ax(c.label)]
    del mod.labeled_conjs[:]
    mod.labeled_conjs.extend(new_conjs)

    # filter the inits

    new_inits = [c for c in mod.labeled_inits if keep_ax(c.label)]
    del mod.labeled_inits[:]
    mod.labeled_inits.extend(new_inits)

    # filter the axioms
    dropped_axioms = [a for a in mod.labeled_axioms if not keep_ax(a.label)]
    mod.labeled_axioms = [a for a in mod.labeled_axioms if keep_ax(a.label)]
    mod.labeled_props = [a for a in mod.labeled_props if keep_ax(a.label)]

    # convert the properties not being verified to axioms
    mod.labeled_axioms.extend(
        [a for a in mod.labeled_props if not check_pr(a.label)])
    mod.labeled_props = [a for a in mod.labeled_props if check_pr(a.label)]

    # filter definitions
    mod.concepts = [
        c for c in mod.concepts
        if startswith_eq_some(c.args[0].func.name, present, mod)
    ]

    # filter the signature
    # keep only the symbols referenced in the remaining
    # formulas

    asts = []
    for x in [
            mod.labeled_axioms, mod.labeled_props, mod.labeled_inits,
            mod.labeled_conjs
    ]:
        asts += [y.formula for y in x]
    asts += mod.concepts
    asts += [action for action in new_actions.values()]
    sym_names = set(x.name for x in lu.used_symbols_asts(asts))

    if filter_symbols.get() or cone_of_influence.get():
        old_syms = list(mod.sig.symbols)
        for sym in old_syms:
            if sym not in sym_names:
                del mod.sig.symbols[sym]

    # check that any dropped axioms do not refer to the isolate's signature
    # and any properties have dependencies present

    def pname(s):
        return s.label if s.label else ""

    if enforce_axioms.get():
        for a in dropped_axioms:
            for x in lu.used_symbols_ast(a.formula):
                if x.name in sym_names:
                    raise iu.IvyError(
                        a, "relevant axiom {} not enforced".format(pname(a)))
        for actname, action in mod.actions.iteritems():
            if startswith_eq_some(actname, present, mod):
                for c in action.iter_calls():
                    called = mod.actions[c]
                    if not startswith_eq_some(c, present, mod):
                        if not (type(called) == ia.Sequence
                                and not called.args):
                            raise iu.IvyError(
                                None,
                                "No implementation for action {}".format(c))
        for p, ds in prop_deps:
            for d in ds:
                if not startswith_eq_some(d, present, mod):
                    raise iu.IvyError(
                        p,
                        "property {} depends on abstracted object {}".format(
                            pname(p), d))


#    for x,y in new_actions.iteritems():
#        print iu.pretty(ia.action_def_to_str(x,y))

# check for interference

#    iu.dbg('list(summarized_actions)')
    check_interference(mod, new_actions, summarized_actions)

    # After checking, we can put in place the new action definitions

    mod.public_actions.clear()
    mod.public_actions.update(exported)
    mod.actions.clear()
    mod.actions.update(new_actions)

    # TODO: need a better way to filter signature
    # new_syms = set(s for s in mod.sig.symbols if keep_sym(s))
    # for s in list(mod.sig.symbols):
    #     if s not in new_syms:
    #         del mod.sig.symbols[s]

    # strip the isolate parameters

    strip_isolate(mod, isolate, impl_mixins, extra_strip)

    # collect the initial condition

    init_cond = ivy_logic.And(*(lf.formula for lf in mod.labeled_inits))
    mod.init_cond = lu.formula_to_clauses(init_cond)
Esempio n. 14
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
Esempio n. 15
0
 def get_next_sym(self,v):
     enc = self.encoding[v]
     abits = self.sub.sym_next_vals(enc)
     bits = [il.And() if b == '1' else il.Or() for b in abits]
     return self.decode_val(bits,v)
Esempio n. 16
0
def invariance_tactic(prover,goals,proof):
    goal = goals[0]                  # pick up the first proof goal
    conc = ipr.goal_conc(goal)       # get its conclusion
    if not isinstance(conc,TemporalModels):
        raise iu.IvyError(proof,'proof goal is not temporal')
    model = conc.model
    fmla = conc.fmla
    if not isinstance(fmla,il.Globally):
        raise iu.IvyError(proof,'invariance tactic applies only to globally formulas')
    invar = fmla.args[0]
    if il.is_temporal(invar):
        raise iu.IvyError(proof,'invariance tactic applies only formulas "globally p"' +
                       ' where p is non-temporal')

    # Collect the auxiliary invariants
    invars = [inv.compile() for inv in proof.tactic_decls]

    # Add the invariant phi to the list
    invars.append(ipr.clone_goal(goal,[],invar))

    # Add the invariant list to the model
    model = model.clone([])
    model.invars = model.invars + invars
    
    # Get all the implicit globally properties from the proof
    # environment. Each temporal operator has an 'environment'. The
    # operator applies to states *not* in actions labeled with this
    # environment. This has several consequences:
    #
    # 1) The operator's semantic constraint is an assumed invariant (i.e.,
    # it holds outside of any action)
    #
    # 2) An 'event' for the temporal operator occurs when (a) we return
    # from an execution context inside its environment to one outside,
    # or (b) we are outside the environment of the operator and some symbol
    # occurring in it's body is mutated.
    #
    # 3) At any event for the operator, we update its truth value and
    # and re-establish its senatic constraint.
    #
    #
    # The following procedure instruments a statement with operator events for
    # both the property to be proved and the invariant assumptions (all G properties here).
    # This depends on the statement's environment, that is, current set of environment
    # labels.
    #
    # Currently, the environment labels of a statement have to be
    # statically determined, but this could change, i.e., the labels
    # could be represented by boolean variables. 
    #
    # TODO: there is something a bit inelegant here, because when we return from
    # an exported action to the external environment, we need to update the operator
    # states, however, we do *not* want to do this when returning to in internal caller.
    # The best solution currently for this is to duplication the actions so there
    # is one version for internal callers and one for external callers. This issue doesn't
    # affect this simple invariance tactic, because it doesn't need to update the truth
    # values of the operators.
    
    # Get all the G properties from the prover environment as assumptions
    
    assumed_gprops = [x for x in prover.axioms if not x.explicit and x.temporal and il.is_gprop(x.formula)]
    gprops = [x.formula for x in assumed_gprops]
    gproplines = [x.lineno for x in assumed_gprops]
    
    # We represent the property G phi to be proved by its negation F ~phi.
    gprops.append(il.Eventually(fmla.environ,il.Not(invar)))
    gproplines.append(goal.lineno)

    # Make some memo tables

    envprops = defaultdict(list)
    symprops = defaultdict(list)
    for prop in gprops:
        envprops[prop.environ].append(prop)
        for sym in ilu.symbols_ast(prop):
            symprops[sym].append(prop)
    actions = dict((b.name,b.action) for b in model.bindings)
    lines = dict(zip(gprops,gproplines))
            
    def instr_stmt(stmt,labels):

        # first, recur on the sub-statements
        args = [instr_stmt(a,labels) if isinstance(a,iact.Action) else a for a in stmt.args]
        res = stmt.clone(args)

        # now add any needed temporal events after this statement
        event_props = set()

        # first, if it is a call, we must consider any events associated with
        # the return
        
        if isinstance(stmt,iact.CallAction):
            callee = actions[stmt.callee()]  # get the called action
            exiting = [l for l in callee.labels if l not in labels] # environments we exit on return
            for label in exiting:
                for prop in envprops[label]:
                    event_props.add(prop)

        # Second, if a symbol is modified, we must add events for every property that
        # depends on the symbol, but only if we are not in the environment of that property. 
                    
        for sym in stmt.modifies():
            for prop in symprops[sym]:
                if prop.environ not in labels:
                    event_props.add(prop)
                    
        # Now, for every property event, we update the property state (none in this case)
        # and also assert the property semantic constraint. 

        events = [prop_event(prop,lines[prop]) for prop in event_props]
        res =  iact.postfix_action(res,events)
        stmt.copy_formals(res) # HACK: This shouldn't be needed
        return res

    # Add property events to all of the actions:

    model.bindings = [b.clone([b.action.clone([instr_stmt(b.action.stmt,b.action.labels)])])
                      for b in model.bindings]
    
    # Add all the assumed invariants to the model

    model.asms.extend([p.clone([p.label,p.formula.args[0]]) for p in assumed_gprops])
    
    # if len(gprops) > 0:
    #     assumes = [gprop_to_assume(x) for x in gprops]
    #     model.bindings = [b.clone([prefix_action(b.action,assumes)]) for b in model.bindings]

    # Change the conclusion formula to M |= true
    conc = TemporalModels(model,il.And())

    # Build the new goal
    goal = ipr.clone_goal(goal,ipr.goal_prems(goal),conc)

    # Return the new goal stack

    goals = [goal] + goals[1:]
    return goals
Esempio n. 17
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()
Esempio n. 18
0
def isolate_component(mod,isolate_name):
    if isolate_name not in mod.isolates:
        raise iu.IvyError(None,"undefined isolate: {}".format(isolate_name))
    isolate = mod.isolates[isolate_name]
    verified = set(a.relname for a in isolate.verified())
    present = set(a.relname for a in isolate.present())
    present.update(verified)
    if not interpret_all_sorts:
        for type_name in list(ivy_logic.sig.interp):
            if not startswith_eq_some(type_name,present):
                del ivy_logic.sig.interp[type_name]
    delegates = set(s.delegated() for s in mod.delegates if not s.delegee())
    delegated_to = dict((s.delegated(),s.delegee()) for s in mod.delegates if s.delegee())
    derived = set(df.args[0].func.name for df in mod.concepts)
    for name in present:
        if (name not in mod.hierarchy
            and name not in ivy_logic.sig.sorts
            and name not in derived
            and name not in ivy_logic.sig.interp):
            raise iu.IvyError(None,"{} is not a module instance, sort, definition, or interpreted function".format(name))
    
    new_actions = {}
    use_mixin = lambda name: startswith_some(name,present)
    mod_mixin = lambda m: m if startswith_some(name,verified) else m.prefix_calls('ext:')
    all_mixins = lambda m: True
    no_mixins = lambda m: False
    after_mixins = lambda m: isinstance(m,ivy_ast.MixinAfterDef)
    before_mixins = lambda m: isinstance(m,ivy_ast.MixinBeforeDef)
    delegated_to_verified = lambda n: n in delegated_to and startswith_eq_some(delegated_to[n],verified)
    ext_assumes = lambda m: before_mixins(m) and not delegated_to_verified(m.mixer())
    for actname,action in mod.actions.iteritems():
        ver = startswith_some(actname,verified)
        pre = startswith_some(actname,present)
        if pre: 
            if not ver:
                assert hasattr(action,'lineno')
                assert hasattr(action,'formal_params'), action
                ext_action = action.assert_to_assume().prefix_calls('ext:')
                assert hasattr(ext_action,'lineno')
                assert hasattr(ext_action,'formal_params'), ext_action
                if actname in delegates:
                    int_action = action.prefix_calls('ext:')
                    assert hasattr(int_action,'lineno')
                    assert hasattr(int_action,'formal_params'), int_action
                else:
                    int_action = ext_action
                    assert hasattr(int_action,'lineno')
                    assert hasattr(int_action,'formal_params'), int_action
            else:
                int_action = ext_action = action
                assert hasattr(int_action,'lineno')
                assert hasattr(int_action,'formal_params'), int_action
            # internal version of the action has mixins checked
            new_actions[actname] = add_mixins(mod,actname,int_action,no_mixins,use_mixin,lambda m:m)
            # external version of the action assumes mixins are ok, unless they
            # are delegated to a currently verified object
            new_action = add_mixins(mod,actname,ext_action,ext_assumes,use_mixin,mod_mixin)
            new_actions['ext:'+actname] = new_action
            # TODO: external version is public if action public *or* called from opaque
            # public_actions.add('ext:'+actname)
        else:
            # TODO: here must check that summarized action does not
            # have a call dependency on the isolated module
            action = summarize_action(action)
            new_actions[actname] = add_mixins(mod,actname,action,after_mixins,use_mixin,mod_mixin)
            new_actions['ext:'+actname] = add_mixins(mod,actname,action,all_mixins,use_mixin,mod_mixin)


    # figure out what is exported:
    exported = set()
    for e in mod.exports:
        if not e.scope() and startswith_some(e.exported(),present): # global scope
            exported.add('ext:' + e.exported())
    for actname,action in mod.actions.iteritems():
        if not startswith_some(actname,present):
            for c in action.iter_calls():
                if startswith_some(c,present):
                    exported.add('ext:' + c)
#    print "exported: {}".format(exported)


    # We allow objects to reference any symbols in global scope, and
    # we keep axioms declared in global scope. Because of the way
    # thigs are named, this gives a different condition for keeping
    # symbols and axioms (in particular, axioms in global scope have
    # label None). Maybe this needs to be cleaned up.

    keep_sym = lambda name: (iu.ivy_compose_character not in name
                            or startswith_eq_some(name,present))
    
    keep_ax = lambda name: (name is None or startswith_eq_some(name.rep,present))


    # filter the conjectures

    new_conjs = [c for c in mod.labeled_conjs if keep_ax(c.label)]
    del mod.labeled_conjs[:]
    mod.labeled_conjs.extend(new_conjs)

    # filter the signature

    # TODO: need a better way to filter signature
    # new_syms = set(s for s in mod.sig.symbols if keep_sym(s))
    # for s in list(mod.sig.symbols):
    #     if s not in new_syms:
    #         del mod.sig.symbols[s]

    # filter the inits


    new_inits = [c for c in mod.labeled_inits if keep_ax(c.label)]
    del mod.labeled_inits[:]
    mod.labeled_inits.extend(new_inits)
    
    init_cond = ivy_logic.And(*(lf.formula for lf in new_inits))
    im.module.init_cond = lu.formula_to_clauses(init_cond)

    # filter the axioms
    mod.labeled_axioms = [a for a in mod.labeled_axioms if keep_ax(a.label)]

    # filter definitions
    mod.concepts = [c for c in mod.concepts if startswith_eq_some(c.args[0].func.name,present)]

    mod.public_actions.clear()
    mod.public_actions.update(exported)
    mod.actions.clear()
    mod.actions.update(new_actions)