Example #1
0
 def recur(action,annot,env,pos=None):
     if isinstance(annot,ia.RenameAnnotation):
         save = dict()
         for x,y in annot.map.iteritems():
             if x in env:
                 save[x] = env[x]
             env[x] = env.get(y,y)
         recur(action,annot.arg,env,pos)
         env.update(save)
         return
     if isinstance(action,ia.Sequence):
         if pos is None:
             pos = len(action.args)
         if pos == 0:
             assert isinstance(annot,ia.EmptyAnnotation),annot
             return
         if not isinstance(annot,ia.ComposeAnnotation):
             iu.dbg('len(action.args)')
             iu.dbg('pos')
             iu.dbg('annot')
         assert isinstance(annot,ia.ComposeAnnotation)
         recur(action,annot.args[0],env,pos-1)
         recur(action.args[pos-1],annot.args[1],env)
         return
     if isinstance(action,ia.IfAction):
         assert isinstance(annot,ia.IteAnnotation),annot
         rncond = env.get(annot.cond,annot.cond)
         try:
             cond = handler.eval(rncond)
         except KeyError:
             print '{}skipping conditional'.format(action.lineno)
             iu.dbg('str_map(env)')
             iu.dbg('env.get(annot.cond,annot.cond)')
             return
         if cond:
             recur(action.args[1],annot.thenb,env)
         else:
             if len(action.args) > 2:
                 recur(action.args[2],annot.elseb,env)
         return
     if isinstance(action,ia.ChoiceAction):
         assert isinstance(annot,ia.IteAnnotation)
         annots = unite_annot(annot)
         assert len(annots) == len(action.args)
         for act,(cond,ann) in reversed(zip(action.args,annots)):
             if handler.eval(cond):
                 recur(act,ann,env)
                 return
         assert False,'problem in match_annotation'
     if isinstance(action,ia.CallAction):
         callee = im.module.actions[action.args[0].rep]
         seq = ia.Sequence(*([ia.Sequence() for x in callee.formal_params]
                          + [callee] 
                          + [ia.Sequence() for x in callee.formal_returns]))
         recur(seq,annot,env)
         return
     if isinstance(action,ia.LocalAction):
         recur(action.args[-1],annot,env)
         return
     handler.handle(action,env)
Example #2
0
def check_concretely_sorted(term,no_error=False,unsorted_var_names=()):
    for x in chain(lu.used_variables(term),lu.used_constants(term)):
        if lg.contains_topsort(x.sort) or lg.is_polymorphic(x.sort):
            iu.dbg('unsorted_var_names')
            iu.dbg('x.name')
            if x.name not in unsorted_var_names:
                if no_error:
                    raise lg.SortError
                raise IvyError(None,"cannot infer sort of {} in {}".format(x,term))
Example #3
0
def get_model_clauses(clauses1):
    s = z3.Solver()
    z3c = clauses_to_z3(clauses1)
    s.add(z3c)
    iu.dbg('"before check"')
    res = s.check()
    iu.dbg('"after check"')
    if res == z3.unsat:
        return None
    m = get_model(s)
    return HerbrandModel(s, m, used_symbols_clauses(clauses1))
Example #4
0
def get_model_clauses(clauses1):
    s = z3.Solver()
    z3c = clauses_to_z3(clauses1)
    s.add(z3c)
    iu.dbg('"before check"')
    res = s.check()
    iu.dbg('"after check"')
    if res == z3.unsat:
        return None
    m = get_model(s)
    return HerbrandModel(s,m,used_symbols_clauses(clauses1))
Example #5
0
def check_conjectures(kind,msg,ag,state):
    failed = itp.undecided_conjectures(state)
    if failed:
        if diagnose.get():
            print "{} failed.".format(kind)
            iu.dbg('ag.states[0].clauses')
            gui = ui.new_ui()
            agui = gui.add(ag)
            gui.tk.update_idletasks() # so that dialog is on top of main window
            agui.try_conjecture(state,msg="{}\nChoose one to see counterexample.".format(msg),bound=1)
            gui.tk.mainloop()
            exit(1)
        raise iu.IvyError(None,"{} failed.".format(kind))
Example #6
0
 def __call__(self,s):
     if s.startswith('$'):
         path = s[1:].split('.')
         num = int(path[0])-1
         if num < 0 or num >= len(self.anchor.args):
             raise iu.IvyError(None,'event has no argument {}'.format(s))
         res = self.anchor.args[num]
         for field in path[1:]:
             if not isinstance(res,DictValue) or field not in res:
                 raise iu.IvyError(None,'value has no field {}'.format(field))
             res = res[field]
         iu.dbg('res')
         return res
     return Symbol(s)
Example #7
0
def compile_action_def(a,sig):
    sig = sig.copy()
    if not hasattr(a.args[1],'lineno'):
        print a
    assert hasattr(a.args[1],'lineno')
    with sig:
        with ASTContext(a.args[1]):
            params = a.args[0].args
            pformals = [v.to_const('prm:') for v in params] 
            if params:
                subst = dict((x.rep,y) for x,y in zip(params,pformals))
                a = ivy_ast.substitute_ast(a,subst)
                assert hasattr(a.args[1],'lineno')
    #            a = ivy_ast.subst_prefix_atoms_ast(a,subst,None,None)
    #            print "after: %s" % (a)
            # convert object paramaters to arguments (object-orientation!)
            formals =  [compile_const(v,sig) for v in pformals + a.formal_params]
            returns = [compile_const(v,sig) for v in a.formal_returns]
    #        print returns
            res = sortify(a.args[1])
            assert hasattr(res,'lineno'), res
            for suba in res.iter_subactions():
                if isinstance(suba,CallAction):
                    if any(lu.used_variables_ast(a) for a in suba.args[0].args):
                        iu.dbg('a.args[0]')
                        iu.dbg('a.formal_params')
                        iu.dbg('suba.lineno')
                        iu.dbg('suba')
                        raise iu.IvyError(suba,"call may not have free variables")
            res.formal_params = formals
            res.formal_returns = returns
            res.label = a.args[0].relname
            return res
Example #8
0
 def __call__(self, s):
     if s.startswith('$'):
         path = s[1:].split('.')
         num = int(path[0]) - 1
         if num < 0 or num >= len(self.anchor.args):
             raise iu.IvyError(None, 'event has no argument {}'.format(s))
         res = self.anchor.args[num]
         for field in path[1:]:
             if not isinstance(res, DictValue) or field not in res:
                 raise iu.IvyError(None,
                                   'value has no field {}'.format(field))
             res = res[field]
         iu.dbg('res')
         return res
     return Symbol(s)
Example #9
0
def check_conjectures(kind, msg, ag, state):
    failed = itp.undecided_conjectures(state)
    if failed:
        if diagnose.get():
            print "{} failed.".format(kind)
            iu.dbg('ag.states[0].clauses')
            gui = ui.new_ui()
            agui = gui.add(ag)
            gui.tk.update_idletasks(
            )  # so that dialog is on top of main window
            agui.try_conjecture(
                state,
                msg="{}\nChoose one to see counterexample.".format(msg),
                bound=1)
            gui.tk.mainloop()
            exit(1)
        raise iu.IvyError(None, "{} failed.".format(kind))
Example #10
0
def get_mixin_order(iso,mod):
    arcs = [(rdf.args[0].relname,rdf.args[1].relname) for rdf in mod.mixord]
    actions = mod.mixins.keys()
    for action in actions:
        mixins = mod.mixins[action]
        mixers = iu.topological_sort(list(set(m.mixer() for m in mixins)),arcs)
        iu.dbg('mixers')
        keymap = dict((x,y) for y,x in enumerate(mixers))
        key = lambda m: keymap[m.mixer()]
        before = sorted([m for m in mixins if isinstance(m,ivy_ast.MixinBeforeDef)],key=key)
        after = sorted([m for m in mixins if isinstance(m,ivy_ast.MixinAfterDef)],key=key)
#        order = SortOrder(arcs)
#        before = sorted([m for m in mixins if isinstance(m,ivy_ast.MixinBeforeDef)],order)
#        after = sorted([m for m in mixins if isinstance(m,ivy_ast.MixinAfterDef)],order)
        before.reverse() # add the before mixins in reverse order
        mixins = before + after
#        print 'mixin order for action {}:'
#        for m in mixins:
#            print m.args[0]
        mod.mixins[action] = mixins
Example #11
0
 def try_conjecture(self,node,conj=None,msg=None,bound=None):
     if conj == None:
         udc = undecided_conjectures(node)
         udc_text = [repr(clauses_to_formula(conj)) for conj in udc]
         msg = msg or "Choose a conjecture to prove:"
         cmd = lambda idx: self.try_conjecture(node,udc[idx],bound=bound)
         self.ui_parent.listbox_dialog(msg,udc_text,command=cmd)
     else:
         if hasattr(conj,'lineno'):
             filename,lineno = conj.lineno
             self.ui_parent.browse(filename,lineno)
         dual = dual_clauses(conj)
         if self.mode.get() == "induction":
             iu.dbg('node.clauses')
             iu.dbg('dual')
             self.bmc(node,dual,bound=bound)
         else:
             sg = self.g.concept_graph(node)
             sg.current.add_constraints(dual.conjuncts)
             self.show_graph(sg)
Example #12
0
 def __call__(self,x,y):
     x = x.args[0].relname
     y = y.args[0].relname
     iu.dbg('x')
     iu.dbg('y')
     res =  -1 if y in self.arcs[x] else 1 if x in self.arcs[y] else 0   
     iu.dbg('res')
     return res
Example #13
0
def sort_infer_list(terms,sorts=None,no_error=False,unsorted_var_names=()):
    iu.dbg('[str(t) for t in terms]')
    iu.dbg('sorts')
    res = concretize_terms(terms,sorts)
    for term in res:
        check_concretely_sorted(term,no_error,unsorted_var_names)
    iu.dbg('res')
    return res
Example #14
0
def rename_vars_no_clash(fmlas1,fmlas2):
    """ Rename the free variables in formula list fmlas1
    so they occur nowhere in fmlas2, avoiding capture """
    uvs = lu.used_variables(*fmlas2)
    uvs = lu.union(uvs,lu.bound_variables(*fmlas1))
    iu.dbg('uvs')
    rn = iu.UniqueRenamer('',(v.name for v in uvs))
    vs = lu.free_variables(*fmlas1)
    iu.dbg('vs')
    vmap = dict((v,Variable(rn(v.name),v.sort)) for v in vs)
    iu.dbg('vmap')
    return [lu.substitute(f,vmap) for f in fmlas1]
Example #15
0
def compile_action_def(a, sig):
    sig = sig.copy()
    if not hasattr(a.args[1], 'lineno'):
        print a
    assert hasattr(a.args[1], 'lineno')
    with sig:
        with ASTContext(a.args[1]):
            params = a.args[0].args
            pformals = [v.to_const('prm:') for v in params]
            if params:
                subst = dict((x.rep, y) for x, y in zip(params, pformals))
                a = ivy_ast.substitute_ast(a, subst)
                assert hasattr(a.args[1], 'lineno')
    #            a = ivy_ast.subst_prefix_atoms_ast(a,subst,None,None)
    #            print "after: %s" % (a)
    # convert object paramaters to arguments (object-orientation!)
            formals = [
                compile_const(v, sig) for v in pformals + a.formal_params
            ]
            returns = [compile_const(v, sig) for v in a.formal_returns]
            #        print returns
            res = sortify(a.args[1])
            assert hasattr(res, 'lineno'), res
            for suba in res.iter_subactions():
                if isinstance(suba, CallAction):
                    if any(
                            lu.used_variables_ast(a)
                            for a in suba.args[0].args):
                        iu.dbg('a.args[0]')
                        iu.dbg('a.formal_params')
                        iu.dbg('suba.lineno')
                        iu.dbg('suba')
                        raise iu.IvyError(suba,
                                          "call may not have free variables")
            res.formal_params = formals
            res.formal_returns = returns
            res.label = a.args[0].relname
            return res
Example #16
0
    def action_update(self, domain, pvars):
        lhs, rhs = self.args
        n = lhs.rep

        # Handle the hierarchical case
        if n in domain.hierarchy:
            asgns = [
                postfix_atoms_ast(self, Atom(x, []))
                for x in domain.hierarchy[n]
            ]
            res = unzip_append(
                [asgn.action_update(domain, pvars) for asgn in asgns])
            return res

        # If the lhs application is partial, make it total by adding parameters
        xtra = len(lhs.rep.sort.dom) - len(lhs.args)
        if xtra < 0:
            raise IvyError(self,
                           "too many parameters in assignment to " + lhs.rep)
        if xtra > 0:
            extend = sym_placeholders(lhs.rep)[-xtra:]
            extend = variables_distinct_list_ast(extend,
                                                 self)  # get unused variables
            lhs = add_parameters_ast(lhs, extend)
            # Assignment of individual to a boolean is a special case
            if is_individual_ast(rhs) and not is_individual_ast(lhs):
                rhs = eq_atom(extend[-1],
                              add_parameters_ast(rhs, extend[0:-1]))
            else:
                rhs = add_parameters_ast(rhs, extend)

        lhs_vars = used_variables_ast(lhs)
        if any(v not in lhs_vars for v in used_variables_ast(rhs)):
            raise IvyError(self, "multiply assigned: {}".format(lhs.rep))

        type_check(domain, rhs)
        if is_individual_ast(lhs) != is_individual_ast(rhs):
            #            print type(lhs.rep)
            #            print str(lhs.rep)
            #            print type(lhs.rep.sort)
            #            print "lhs: %s: %s" % (lhs,type(lhs))
            #            print "rhs: %s: %s" % (rhs,type(rhs))
            raise IvyError(self,
                           "sort mismatch in assignment to {}".format(lhs.rep))

        # For a destructor assignment, we actually mutate the first argument

        if n.name in ivy_module.module.destructor_sorts:
            mut = lhs.args[0]
            rest = list(lhs.args[1:])
            mut_n = mut.rep
            nondet = mut_n.suffix("_nd").skolem()
            new_clauses = mk_assign_clauses(mut_n,
                                            nondet(*sym_placeholders(mut_n)))
            fmlas = []
            nondet_lhs = lhs.rep(*([nondet(*mut.args)] + rest))
            fmlas.append(equiv_ast(nondet_lhs, rhs))
            vs = sym_placeholders(n)
            dlhs = n(*([nondet(*mut.args)] + vs[1:]))
            drhs = n(*([mut] + vs[1:]))
            eqs = [
                eq_atom(v, a) for (v, a) in zip(vs, lhs.args)[1:]
                if not isinstance(a, Variable)
            ]
            if eqs:
                fmlas.append(Or(And(*eqs), equiv_ast(dlhs, drhs)))
            new_clauses = and_clauses(new_clauses, Clauses(fmlas))
            dbg('new_clauses')
            return ([mut_n], new_clauses, false_clauses())

        new_clauses = mk_assign_clauses(lhs, rhs)
        #        print "assign new_clauses = {}".format(new_clauses)
        return ([n], new_clauses, false_clauses())
Example #17
0
 def map(self, fun):
     iu.dbg('fun')
     return fun(self.name)
Example #18
0
 def map(self,fun):
     iu.dbg('fun')
     return fun(self.name)
Example #19
0
 def __init__(self,arcs):
     self.arcs = arcs
     iu.dbg('arcs')
Example #20
0
        usage()
    with im.Module():
        isolate = ivy_compiler.isolate.get()
        ivy.source_file(sys.argv[1],ivy.open_read(sys.argv[1]),create_isolate=False)

        # If user specifies an isolate, check it. Else, if any isolates
        # are specificied in the file, check all, else check globally.

        if isolate != None:
            isolates = [isolate]
        else:
            isolates = sorted(list(im.module.isolates))
            if len(isolates) == 0:
                isolates = [None]

        for isolate in isolates:
            if len(im.module.isolates[isolate].verified()) == 0:
                continue # skip if nothing to verify
            iu.dbg('isolate')
            with im.module.copy():
                ivy_isolate.create_isolate(isolate)
                ag = ivy_art.AnalysisGraph(initializer=ivy_alpha.alpha)
                with utl.ErrorPrinter():
                    with ivy_interp.EvalContext(check=False):
                        ag.execute_action('ext')
                        cex = ag.check_bounded_safety(ag.states[-1])
                        if cex is not None:
                            display_cex("safety failed",cex)
    print "OK"

Example #21
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